diff --git a/.github/scripts/format-go-code.sh b/.github/scripts/format-go-code.sh
index 33063ce42..03420092e 100755
--- a/.github/scripts/format-go-code.sh
+++ b/.github/scripts/format-go-code.sh
@@ -6,12 +6,15 @@ FILEPATH="$1"
gofmt -s -w "$FILEPATH"
-# https://github.com/rinchsan/gosimports
+# https://github.com/daixiang0/gci
if [[ "$FILEPATH" == *"tests/slo/"* ]]
then
- gosimports -local slo -w "$FILEPATH"
+ gci write --skip-generated -s standard -s default -s "prefix(slo)" "$FILEPATH"
+elif [[ "$FILEPATH" == *"examples/"* ]]
+then
+ gci write --skip-generated -s standard -s default -s "prefix(examples)" "$FILEPATH"
else
- gosimports -local github.com/ydb-platform/ydb-go-sdk/v3 -w "$FILEPATH"
+ gci write --skip-generated -s standard -s default -s "prefix(github.com/ydb-platform/ydb-go-sdk/v3)" "$FILEPATH"
fi
diff --git a/.github/workflows/breaking.yml b/.github/workflows/breaking.yml
index 1670c6f64..17eeb19c3 100644
--- a/.github/workflows/breaking.yml
+++ b/.github/workflows/breaking.yml
@@ -11,6 +11,9 @@ jobs:
group: broken-changes-${{ github.ref }}
cancel-in-progress: true
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ contents: read
steps:
- name: Install Go
uses: actions/setup-go@v3
@@ -22,6 +25,8 @@ jobs:
run: test -e ~/go/bin/gorelease || go install golang.org/x/exp/cmd/gorelease@latest
- name: Check broken API changes
run: gorelease -base=$GITHUB_BASE_REF 2>&1 > changes.txt | true
+ - name: Print API changes
+ run: cat changes.txt
- name: Comment Report
if: always()
uses: marocchino/sticky-pull-request-comment@v2
diff --git a/.github/workflows/check-codegen.yml b/.github/workflows/check-codegen.yml
index a4be45c6f..0ee6bd406 100644
--- a/.github/workflows/check-codegen.yml
+++ b/.github/workflows/check-codegen.yml
@@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest ]
- go-version: [1.20.x, 1.21.x]
+ go-version: [1.21.x, 1.22.x]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
@@ -32,7 +32,8 @@ jobs:
- name: Build
run: |
go install ./internal/cmd/gtrace
- go install go.uber.org/mock/mockgen@892b665398ecece7c7a900d2a2f2fa3dac07e4c4
+ go install ./internal/cmd/gstack
+ go install go.uber.org/mock/mockgen@v0.4.0
- name: Clean and re-generate *_gtrace.go files
run: |
@@ -40,5 +41,9 @@ jobs:
go generate ./trace
go generate ./...
+ - name: Re-generate stack.FunctionID calls
+ run: |
+ gstack .
+
- name: Check repository diff
run: bash ./.github/scripts/check-work-copy-equals-to-committed.sh "code-generation not equal with committed"
diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml
index 39fc2f4d7..745864a37 100644
--- a/.github/workflows/examples.yml
+++ b/.github/workflows/examples.yml
@@ -15,11 +15,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- ydb-version: [ 22.5, 23.1, 23.2 ]
- application: [ native, database_sql, gorm, xorm ]
+ ydb-version: [ 23.3, 24.1 ]
+ application: [ native/table, native/query, database_sql, gorm, xorm ]
services:
ydb:
- image: cr.yandex/crpsjg1coh47p81vh2lc/yandex-docker-local-ydb:${{ matrix.ydb-version }}
+ image: ydbplatform/local-ydb:${{ matrix.ydb-version }}
ports:
- 2135:2135
- 2136:2136
@@ -29,11 +29,13 @@ jobs:
env:
YDB_LOCAL_SURVIVE_RESTART: true
YDB_USE_IN_MEMORY_PDISKS: true
+ YDB_TABLE_ENABLE_PREPARED_DDL: true
options: '-h localhost'
env:
OS: ubuntu-latest
YDB_CONNECTION_STRING: grpc://localhost:2136/local
YDB_ANONYMOUS_CREDENTIALS: 1
+ YDB_VERSION: ${{ matrix.ydb-version }}
steps:
- name: Checkout code
uses: actions/checkout@v3
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index d62b7849e..c4b89aa7a 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -69,7 +69,7 @@ jobs:
- name: Install utilities
run: |
go install mvdan.cc/gofumpt@v0.3.1
- go install github.com/rinchsan/gosimports/cmd/gosimports@v0.1.5
+ go install github.com/daixiang0/gci@v0.12.1
- name: format all files with auto-formatter
run: bash ./.github/scripts/format-all-go-code.sh "$PWD"
- name: Check repository diff
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index fb3f63aa4..61361f822 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -70,7 +70,7 @@ jobs:
TAG="v$MAJOR.$MINOR.$PATCH";
fi;
git tag $TAG
- git push --tags && git push
+ git push && git push --tags
CHANGELOG="$CHANGELOG
Full Changelog: [$LAST_TAG...$TAG](https://github.com/ydb-platform/ydb-go-sdk/compare/$LAST_TAG...$TAG)"
diff --git a/.github/workflows/slo.yml b/.github/workflows/slo.yml
index f60064935..d1922303e 100644
--- a/.github/workflows/slo.yml
+++ b/.github/workflows/slo.yml
@@ -43,29 +43,35 @@ jobs:
timeBetweenPhases: 30
shutdownTime: 30
- language_id0: 'native'
+ language_id0: 'native-table'
workload_path0: 'tests/slo'
- language0: 'Go SDK native'
+ language0: 'Native ydb-go-sdk/v3 over table-service'
workload_build_context0: ../..
- workload_build_options0: -f Dockerfile --build-arg SRC_PATH=native --build-arg JOB_NAME=workload-native
+ workload_build_options0: -f Dockerfile --build-arg SRC_PATH=native/table --build-arg JOB_NAME=workload-native-table
- language_id1: 'databasesql'
+ language_id1: 'native-query'
workload_path1: 'tests/slo'
- language1: 'Go SDK database/sql'
+ language1: 'Native ydb-go-sdk/v3 over query-service'
workload_build_context1: ../..
- workload_build_options1: -f Dockerfile --build-arg SRC_PATH=database/sql --build-arg JOB_NAME=workload-databasesql
+ workload_build_options1: -f Dockerfile --build-arg SRC_PATH=native/query --build-arg JOB_NAME=workload-native-query
- language_id2: 'gorm'
+ language_id2: 'database-sql'
workload_path2: 'tests/slo'
- language2: 'Go SDK gorm'
+ language2: 'Go SDK database/sql'
workload_build_context2: ../..
- workload_build_options2: -f Dockerfile --build-arg SRC_PATH=gorm --build-arg JOB_NAME=workload-gorm
+ workload_build_options2: -f Dockerfile --build-arg SRC_PATH=database/sql --build-arg JOB_NAME=workload-database-sql
- language_id3: 'xorm'
+ language_id3: 'gorm'
workload_path3: 'tests/slo'
- language3: 'Go SDK xorm'
+ language3: 'Go SDK gorm'
workload_build_context3: ../..
- workload_build_options3: -f Dockerfile --build-arg SRC_PATH=xorm --build-arg JOB_NAME=workload-xorm
+ workload_build_options3: -f Dockerfile --build-arg SRC_PATH=gorm --build-arg JOB_NAME=workload-gorm
+
+ language_id4: 'xorm'
+ workload_path4: 'tests/slo'
+ language4: 'Go SDK xorm'
+ workload_build_context4: ../..
+ workload_build_options4: -f Dockerfile --build-arg SRC_PATH=xorm --build-arg JOB_NAME=workload-xorm
- uses: actions/upload-artifact@v3
if: always()
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index d9c87d217..756b2fd38 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- go-version: [1.20.x, 1.21.x]
+ go-version: [1.21.x, 1.22.x]
os: [ubuntu, windows, macOS]
env:
OS: ${{ matrix.os }}-latest
@@ -44,11 +44,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- go-version: [1.20.x, 1.21.x]
- ydb-version: [22.5, 23.1, 23.2, 23.3]
+ go-version: [1.21.x, 1.22.x]
+ ydb-version: [23.3, 24.1]
services:
ydb:
- image: cr.yandex/yc/yandex-docker-local-ydb:${{ matrix.ydb-version }}
+ image: ydbplatform/local-ydb:${{ matrix.ydb-version }}
ports:
- 2135:2135
- 2136:2136
@@ -58,6 +58,7 @@ jobs:
env:
YDB_LOCAL_SURVIVE_RESTART: true
YDB_USE_IN_MEMORY_PDISKS: true
+ YDB_TABLE_ENABLE_PREPARED_DDL: true
options: '-h localhost'
env:
OS: ubuntu-latest
diff --git a/.golangci.yml b/.golangci.yml
index e58998c24..b373a0322 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -64,6 +64,12 @@ linters-settings:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
local-prefixes: github.com/ydb-platform/ydb-go-sdk/v3
+ gci:
+ sections:
+ - standard # Standard section: captures all standard packages.
+ - default # Default section: contains all imports that could not be matched to another section type.
+ - prefix(github.com/ydb-platform/ydb-go-sdk/v3) # Custom section: groups all imports with the specified Prefix.
+ skip-generated: true
goconst:
# minimal length of string constant, 3 by default
min-len: 2
@@ -106,6 +112,10 @@ linters-settings:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
+ gomoddirectives:
+ replace-local: true
+ replace-allow-list:
+ - xorm.io/xorm
gocritic:
disabled-checks:
- whyNoLint # https://github.com/go-critic/go-critic/issues/1063
@@ -213,32 +223,24 @@ linters:
- cyclop
- depguard
- dupl
- - errname
- exhaustive
- exhaustivestruct
- exhaustruct
- forbidigo
- forcetypeassert
- funlen
- - gci
- gochecknoglobals
- gocognit
- godot
- goerr113
- golint
- gomnd
- - gomoddirectives
- ifshort
- interfacebloat
- - interfacer
- ireturn
- maintidx
- - maligned
- - nilerr
- - nlreturn
- nonamedreturns
- paralleltest
- - protogetter
- scopelint
- structcheck
- testableexamples
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5230596b9..f8e848965 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,98 @@
+## v3.59.3
+* Fixed `gstack` logic for parsing `ast.BlockStmt`
+
+## v3.59.2
+* Added internal `gstack` codegen tool for filling `stack.FunctionID` with value from call stack
+
+## v3.59.1
+* Fixed updating last usage timestamp for smart parking of the conns
+
+## v3.59.0
+* Added `Struct` support for `ydb.ParamsBuilder()`
+* Added support of `TzDate`,`TzDateTime`,`TzTimestamp` types in `ydb.ParamsBuilder()`
+* Added `trace.Query.OnTransactionExecute` event
+* Added query pool metrics
+* Fixed logic of query session pool
+* Changed initialization of internal driver clients to lazy
+* Removed `ydb.WithSessionPoolSizeLimit()` option
+* Added async put session into pool if external context is done
+* Dropped intermediate callbacks from `trace.{Table,Retry,Query}` events
+* Wrapped errors from `internal/pool.Pool.getItem` as retryable
+* Disabled the logic of background grpc-connection parking
+* Improved stringification for postgres types
+
+## v3.58.2
+* Added `trace.Query.OnSessionBegin` event
+* Added `trace.Query.OnResult{New,NextPart,NextResultSet,Close}` events
+* Added `trace.Query.OnRow{Scan,ScanNamed,ScanStruct}` events
+
+## v3.58.1
+* Dropped all deprecated callbacks and events from traces
+* Added `trace.Driver.OnConnStream{SendMsg,RecvMsg,CloseSend}` events
+* Added `trace.Query.OnSessionExecute` event
+
+## v3.58.0
+* Changed `List` constructor from `ydb.ParamsBuilder().List().Build().Build()` to `ydb.ParamsBuilder().BeginList().EndList().Build()`
+* Changed `Set` constructor from `ydb.ParamsBuilder().Set().Build().Build()` to `ydb.ParamsBuilder().BeginSet().EndSet().Build()`
+* Changed `Dict` constructor from `ydb.ParamsBuilder().Dict().Build().Build()` to `ydb.ParamsBuilder().BeginDict().EndDict().Build()`
+* Changed `Optional` constructor from `ydb.ParamsBuilder().Set().Build().Build()` to `ydb.ParamsBuilder().BeginOptional().EndOptional().Build()`
+* Added events into `trace.Query` trace
+* Rewrote `internal/pool` to buffered channel
+* Added `internal/xcontext.WithDone()`
+* Added `internal/xsync.{OnceFunc,OnceValue}`
+* Updated `google.golang.org/protobuf` from `v1.31.0` to `v.33.0`
+* Added `ydb.ParamsBuilder().Pg().{Value,Int4,Int8,Unknown}` for postgres arguments
+* Added `Tuple` support for `ydb.ParamsBuilder()`
+
+## v3.57.4
+* Added client pid to each gRPC requests to YDB over header `x-ydb-client-pid`
+* Added `ydb.WithApplicationName` option
+* Added `Dict` support for `ydb.ParamsBuilder()`
+
+## v3.57.3
+* Added metrics over query service internals
+* Added session create and delete events into `trace.Query`
+* Moved public type `query.SessionStatus` into `internal/query` package
+
+## v3.57.2
+* Fixed cases when some option is nil
+
+## v3.57.1
+* Added logs over query service internals
+* Changed `trace.Query` events
+* Changed visibility of `query.{Do,DoTx}Options` from public to private
+
+## v3.57.0
+* Added experimental implementation of query service client
+* Fixed sometime panic on topic writer closing
+* Added experimental query parameters builder `ydb.ParamsBuilder()`
+* Changed types of `table/table.{QueryParameters,ParameterOption}` to aliases on `internal/params.{Parameters,NamedValue}`
+* Fixed bug with optional decimal serialization
+
+## v3.56.2
+* Fixed return private error for commit to stopped partition in topic reader.
+* Stopped wrapping err error as transport error at topic streams (internals)
+
+## v3.56.1
+* Fixed fixenv usage (related to tests only)
+
+## v3.56.0
+* Fixed handle of operational errors in topic streams
+* The minimum version of Go in `ydb-go-sdk` has been raised to `go1.21`
+* Fixed topic writer infinite reconnections in some cases
+* Refactored nil on err `internal/grpcwrapper/rawydb/issues.go`, when golangci-lint nilerr enabled
+* Refactored nil on err `internal/grpcwrapper/rawtopic/describe_topic.go`, when golangci-lint nilerr enabled
+
+## v3.55.3
+* Fixed handle of operational errors in topic streams (backported fix only)
+
+## v3.55.2
+* Fixed init info in topic writer, when autoseq num turned off.
+
+## v3.55.1
+* Supported column name prefix `__discard_column_` for discard columns in result sets
+* Made `StatusIds_SESSION_EXPIRED` retriable for idempotent operations
+
## v3.55.0
* Refactored `internal/value/intervalValue.Yql()`
* The minimum version of Go in `ydb-go-sdk` has been raised to `go1.20`
@@ -12,14 +107,14 @@
## v3.54.2
* Added context to some internal methods for better tracing
-* Added `trace.FunctionID` helper and `FunctionID` field to trace start info's
+* Added `trace.FunctionID` helper and `FunctionID` field to trace start info's
* Replaced lazy initialization of ydb clients (table, topic, etc.) to explicit initialization on `ydb.Open` step
## v3.54.1
-* Fixed inconsistent labels in `metrics`
+* Fixed inconsistent labels in `metrics`
## v3.54.0
-* Allowed `sql.LevelSerializable` isolation level in read-write mode in `database/sql` transactions
+* Allowed `sql.LevelSerializable` isolation level in read-write mode in `database/sql` transactions
* Refactored traces and metrics
* Added `{retry,table}.WithLabel` options for mark retriers calls
* Added `ydb.WithTraceRetry` option
@@ -43,7 +138,7 @@
* Fixed stringification of credentials object
## v3.53.2
-* Fixed panic when try to unwrap values with more than 127 columns with custom ydb unmarshaler
+* Fixed panic when try to unwrap values with more than 127 columns with custom ydb unmarshaler
## v3.53.1
* Bumps `github.com/ydb-platform/ydb-go-genproto` for support `query` service
@@ -192,7 +287,7 @@
* Added `table/options.WithCallOptions` options for append custom grpc call options into `session.{BulkUpsert,Execute,StreamExecuteScanQuery}`
* Supported fake transactions in `database/sql` driver over connector option `ydb.WithFakeTx(queryMode)` and connection string param `go_fake_tx`
* Removed `testutil/timeutil` package (all usages replaced with `clockwork` package)
-* Changed behaviour of retryer on transport errors `cancelled` and `deadline exceeded` - will retry idempotent operation if context is not done
+* Changed behaviour of retryer on transport errors `cancelled` and `deadline exceeded` - will retry idempotent operation if context is not done
* Added address of node to operation error description as optional
* Fixed bug with put session from unknown node
* Fixed bug with parsing of `TzTimestamp` without microseconds
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 53e4c6849..3760cd632 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -56,7 +56,7 @@ go test -race -tags fast ./...
##### All tests
```sh
-docker run -itd --name ydb -dp 2135:2135 -dp 2136:2136 -dp 8765:8765 -v `pwd`/ydb_certs:/ydb_certs -e YDB_LOCAL_SURVIVE_RESTART=true -e YDB_USE_IN_MEMORY_PDISKS=true -h localhost cr.yandex/yc/yandex-docker-local-ydb:latest
+docker run -itd --name ydb -dp 2135:2135 -dp 2136:2136 -dp 8765:8765 -v `pwd`/ydb_certs:/ydb_certs -e YDB_LOCAL_SURVIVE_RESTART=true -e YDB_USE_IN_MEMORY_PDISKS=true -h localhost ydbplatform/local-ydb:latest
export YDB_CONNECTION_STRING="grpcs://localhost:2135/local"
export YDB_SSL_ROOT_CERTIFICATES_FILE="`pwd`/ydb_certs/ca.pem"
export YDB_SESSIONS_SHUTDOWN_URLS="http://localhost:8765/actors/kqp_proxy?force_shutdown=all"
diff --git a/README.md b/README.md
index eb51ff130..66967a039 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
[![WebSite](https://img.shields.io/badge/website-ydb.tech-blue.svg)](https://ydb.tech)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/ydb-platform/ydb-go-sdk/blob/master/CONTRIBUTING.md)
-Supports `table`, `discovery`, `coordination`, `ratelimiter`, `scheme`, `scripting` and `topic` clients for [YDB](https://ydb.tech).
+Supports `table`, `query`, `discovery`, `coordination`, `ratelimiter`, `scheme`, `scripting` and `topic` clients for [YDB](https://ydb.tech).
`YDB` is an open-source Distributed SQL Database that combines high availability and scalability with strict consistency and [ACID](https://en.wikipedia.org/wiki/ACID) transactions.
`YDB` was created primarily for [OLTP](https://en.wikipedia.org/wiki/Online_transaction_processing) workloads and supports some [OLAP](https://en.wikipedia.org/wiki/Online_analytical_processing) scenarious.
@@ -31,19 +31,20 @@ go get -u github.com/ydb-platform/ydb-go-sdk/v3
## Example Usage
* connect to YDB
-```golang
+```go
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
log.Fatal(err)
}
```
-* execute `SELECT` query
- ```golang
-const query = `SELECT 42 as id, "myStr" as myStr;`
-
+* execute `SELECT` query over `Table` service client
+ ```go
// Do retry operation on errors with best effort
-queryErr := db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
- _, res, err := s.Execute(ctx, table.DefaultTxControl(), query, nil)
+err := db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
+ _, res, err := s.Execute(ctx, table.DefaultTxControl(),
+ `SELECT 42 as id, "myStr" as myStr;`,
+ nil, // empty parameters
+ )
if err != nil {
return err
}
@@ -62,12 +63,61 @@ queryErr := db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err e
}
return res.Err() // for driver retry if not nil
})
-if queryErr != nil {
- log.Fatal(queryErr)
+if err != nil {
+ log.Fatal(err)
+}
+```
+* execute `SELECT` query over `Query` service client
+ ```go
+// Do retry operation on errors with best effort
+err := db.Query().Do( // Do retry operation on errors with best effort
+ ctx, // context manage exiting from Do
+ func(ctx context.Context, s query.Session) (err error) { // retry operation
+ _, res, err := s.Execute(ctx, `SELECT 42 as id, "myStr" as myStr;`))
+ if err != nil {
+ return err // for auto-retry with driver
+ }
+ defer func() { _ = res.Close(ctx) }() // cleanup resources
+ for { // iterate over result sets
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ for { // iterate over rows
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ type myStruct struct {
+ id uint64 `sql:"id"`
+ str string `sql:"myStr"`
+ }
+ var s myStruct
+ if err = row.ScanStruct(&s); err != nil {
+ return err // generally scan error not retryable, return it for driver check error
+ }
+ }
+ }
+
+ return res.Err() // return finally result error for auto-retry with driver
+ },
+ query.WithIdempotent(),
+)
+if err != nil {
+ log.Fatal(err)
}
```
+
* usage with `database/sql` (see additional docs in [SQL.md](SQL.md) )
-```golang
+```go
import (
"context"
"database/sql"
@@ -96,7 +146,7 @@ log.Printf("id = %d, myStr = \"%s\"", id, myStr)
```
-More examples of usage placed in [examples](https://github.com/ydb-platform/ydb-go-examples) repository.
+More examples of usage placed in [examples](./examples) directory.
## Credentials
@@ -124,8 +174,7 @@ Next packages provide debug tooling:
| [ydb-go-sdk-zap](https://github.com/ydb-platform/ydb-go-sdk-zap) | logging | logging ydb-go-sdk events with `zap` package | [ydbZap.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-zap/blob/master/internal/cmd/bench/main.go#L64) |
| [ydb-go-sdk-zerolog](https://github.com/ydb-platform/ydb-go-sdk-zerolog) | logging | logging ydb-go-sdk events with `zerolog` package | [ydbZerolog.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-zerolog/blob/master/internal/cmd/bench/main.go#L47) |
| [ydb-go-sdk-logrus](https://github.com/ydb-platform/ydb-go-sdk-logrus) | logging | logging ydb-go-sdk events with `logrus` package | [ydbLogrus.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-logrus/blob/master/internal/cmd/bench/main.go#L48) |
-| [ydb-go-sdk-metrics](https://github.com/ydb-platform/ydb-go-sdk-metrics) | metrics | common metrics of ydb-go-sdk. Package declare interfaces such as `Registry`, `GaugeVec` and `Gauge` and use it for traces | |
-| [ydb-go-sdk-prometheus](https://github.com/ydb-platform/ydb-go-sdk-prometheus) | metrics | prometheus wrapper over [ydb-go-sdk-metrics](https://github.com/ydb-platform/ydb-go-sdk-metrics) | [ydbPrometheus.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-prometheus/blob/master/internal/cmd/bench/main.go#L56) |
+| [ydb-go-sdk-prometheus](https://github.com/ydb-platform/ydb-go-sdk-prometheus/v2) | metrics | prometheus wrapper over [ydb-go-sdk/v3/metrics](https://github.com/ydb-platform/ydb-go-sdk/tree/master/metrics) | [ydbPrometheus.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-prometheus/blob/master/internal/cmd/bench/main.go#L56) |
| [ydb-go-sdk-opentracing](https://github.com/ydb-platform/ydb-go-sdk-opentracing) | tracing | OpenTracing plugin for trace internal ydb-go-sdk calls | [ydbOpentracing.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-opentracing/blob/master/internal/cmd/bench/main.go#L86) |
| [ydb-go-sdk-otel](https://github.com/ydb-platform/ydb-go-sdk-otel) | tracing | OpenTelemetry plugin for trace internal ydb-go-sdk calls | [ydbOtel.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-otel/blob/master/internal/cmd/bench/main.go#L98) |
diff --git a/balancers/balancers.go b/balancers/balancers.go
index f5fa1076e..c73c8f503 100644
--- a/balancers/balancers.go
+++ b/balancers/balancers.go
@@ -40,6 +40,7 @@ func (filterLocalDC) String() string {
func PreferLocalDC(balancer *balancerConfig.Config) *balancerConfig.Config {
balancer.Filter = filterLocalDC{}
balancer.DetectLocalDC = true
+
return balancer
}
@@ -49,6 +50,7 @@ func PreferLocalDC(balancer *balancerConfig.Config) *balancerConfig.Config {
func PreferLocalDCWithFallBack(balancer *balancerConfig.Config) *balancerConfig.Config {
balancer = PreferLocalDC(balancer)
balancer.AllowFallback = true
+
return balancer
}
@@ -61,6 +63,7 @@ func (locations filterLocations) Allow(_ balancerConfig.Info, c conn.Conn) bool
return true
}
}
+
return false
}
@@ -91,6 +94,7 @@ func PreferLocations(balancer *balancerConfig.Config, locations ...string) *bala
}
sort.Strings(locations)
balancer.Filter = filterLocations(locations)
+
return balancer
}
@@ -100,6 +104,7 @@ func PreferLocations(balancer *balancerConfig.Config, locations ...string) *bala
func PreferLocationsWithFallback(balancer *balancerConfig.Config, locations ...string) *balancerConfig.Config {
balancer = PreferLocations(balancer, locations...)
balancer.AllowFallback = true
+
return balancer
}
@@ -129,6 +134,7 @@ func Prefer(balancer *balancerConfig.Config, filter func(endpoint Endpoint) bool
balancer.Filter = filterFunc(func(_ balancerConfig.Info, c conn.Conn) bool {
return filter(c.Endpoint())
})
+
return balancer
}
@@ -138,6 +144,7 @@ func Prefer(balancer *balancerConfig.Config, filter func(endpoint Endpoint) bool
func PreferWithFallback(balancer *balancerConfig.Config, filter func(endpoint Endpoint) bool) *balancerConfig.Config {
balancer = Prefer(balancer, filter)
balancer.AllowFallback = true
+
return balancer
}
diff --git a/balancers/balancers_test.go b/balancers/balancers_test.go
index 2c7c4efd8..75d0758b0 100644
--- a/balancers/balancers_test.go
+++ b/balancers/balancers_test.go
@@ -66,5 +66,6 @@ func applyPreferFilter(info balancerConfig.Info, b *balancerConfig.Config, conns
res = append(res, c)
}
}
+
return res
}
diff --git a/balancers/config.go b/balancers/config.go
index 04623862f..8bc38199c 100644
--- a/balancers/config.go
+++ b/balancers/config.go
@@ -92,6 +92,7 @@ func CreateFromConfig(s string) (*balancerConfig.Config, error) {
if c.Fallback {
return PreferLocalDCWithFallBack(b), nil
}
+
return PreferLocalDC(b), nil
case preferTypeLocations:
if len(c.Locations) == 0 {
@@ -100,6 +101,7 @@ func CreateFromConfig(s string) (*balancerConfig.Config, error) {
if c.Fallback {
return PreferLocationsWithFallback(b, c.Locations...), nil
}
+
return PreferLocations(b, c.Locations...), nil
default:
return b, nil
@@ -114,9 +116,9 @@ func FromConfig(config string, opts ...fromConfigOption) *balancerConfig.Config
b *balancerConfig.Config
err error
)
- for _, o := range opts {
- if o != nil {
- o(&h)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&h)
}
}
@@ -125,6 +127,7 @@ func FromConfig(config string, opts ...fromConfigOption) *balancerConfig.Config
if h.errorHandler != nil {
h.errorHandler(err)
}
+
return h.fallbackBalancer
}
diff --git a/config/config.go b/config/config.go
index 5cf9a0a09..96756e9ec 100644
--- a/config/config.go
+++ b/config/config.go
@@ -161,9 +161,19 @@ func WithTraceRetry(t *trace.Retry, opts ...trace.RetryComposeOption) Option {
}
}
+// WithApplicationName add provided application name to all api requests
+func WithApplicationName(applicationName string) Option {
+ return func(c *Config) {
+ c.metaOptions = append(c.metaOptions, meta.WithApplicationNameOption(applicationName))
+ }
+}
+
+// WithUserAgent add provided user agent to all api requests
+//
+// Deprecated: use WithApplicationName instead
func WithUserAgent(userAgent string) Option {
return func(c *Config) {
- c.metaOptions = append(c.metaOptions, meta.WithUserAgentOption(userAgent))
+ c.metaOptions = append(c.metaOptions, meta.WithApplicationNameOption(userAgent))
}
}
@@ -268,9 +278,9 @@ func ExcludeGRPCCodesForPessimization(codes ...grpcCodes.Code) Option {
func New(opts ...Option) *Config {
c := defaultConfig()
- for _, o := range opts {
- if o != nil {
- o(c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(c)
}
}
@@ -281,9 +291,9 @@ func New(opts ...Option) *Config {
// With makes copy of current Config with specified options
func (c *Config) With(opts ...Option) *Config {
- for _, o := range opts {
- if o != nil {
- o(c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(c)
}
}
c.meta = meta.New(
@@ -292,5 +302,6 @@ func (c *Config) With(opts ...Option) *Config {
c.trace,
c.metaOptions...,
)
+
return c
}
diff --git a/config/defaults.go b/config/defaults.go
index a5dcfeb83..e63867808 100644
--- a/config/defaults.go
+++ b/config/defaults.go
@@ -64,6 +64,7 @@ func defaultGrpcOptions(t *trace.Driver, secure bool, tlsConfig *tls.Config) (op
insecure.NewCredentials(),
))
}
+
return opts
}
@@ -72,6 +73,7 @@ func certPool() *x509.CertPool {
if err == nil {
return certPool
}
+
return x509.NewCertPool()
}
diff --git a/connection.go b/connection.go
index 3e8e3d2a4..9bff94e31 100644
--- a/connection.go
+++ b/connection.go
@@ -5,6 +5,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/coordination"
"github.com/ydb-platform/ydb-go-sdk/v3/discovery"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
"github.com/ydb-platform/ydb-go-sdk/v3/ratelimiter"
"github.com/ydb-platform/ydb-go-sdk/v3/scheme"
"github.com/ydb-platform/ydb-go-sdk/v3/scripting"
@@ -34,6 +35,13 @@ type Connection interface {
// Table returns table client
Table() table.Client
+ // Query returns query client
+ //
+ // # Experimental
+ //
+ // Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+ Query() query.Client
+
// Scheme returns scheme client
Scheme() scheme.Client
diff --git a/coordination/example_test.go b/coordination/example_test.go
index f1e416294..57657d779 100644
--- a/coordination/example_test.go
+++ b/coordination/example_test.go
@@ -14,6 +14,7 @@ func Example() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -28,12 +29,14 @@ func Example() {
})
if err != nil {
fmt.Printf("failed to create node: %v", err)
+
return
}
defer db.Coordination().DropNode(ctx, "/local/test")
e, c, err := db.Coordination().DescribeNode(ctx, "/local/test")
if err != nil {
fmt.Printf("failed to describe node: %v", err)
+
return
}
fmt.Printf("node description: %+v\nnode config: %+v\n", e, c)
diff --git a/discovery/example_test.go b/discovery/example_test.go
index 30ca45b40..87b142ab1 100644
--- a/discovery/example_test.go
+++ b/discovery/example_test.go
@@ -12,12 +12,14 @@ func Example_discoverCluster() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
endpoints, err := db.Discovery().Discover(ctx)
if err != nil {
fmt.Printf("discover failed: %v", err)
+
return
}
fmt.Printf("%s endpoints:\n", db.Name())
@@ -31,12 +33,14 @@ func Example_whoAmI() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
whoAmI, err := db.Discovery().WhoAmI(ctx)
if err != nil {
fmt.Printf("discover failed: %v", err)
+
return
}
fmt.Printf("%s whoAmI: %s\n", db.Name(), whoAmI.String())
diff --git a/driver.go b/driver.go
index 65eb86a81..7adfab361 100644
--- a/driver.go
+++ b/driver.go
@@ -20,6 +20,8 @@ import (
discoveryConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/discovery/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/dsn"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/endpoint"
+ internalQuery "github.com/ydb-platform/ydb-go-sdk/v3/internal/query"
+ queryConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
internalRatelimiter "github.com/ydb-platform/ydb-go-sdk/v3/internal/ratelimiter"
ratelimiterConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/ratelimiter/config"
internalScheme "github.com/ydb-platform/ydb-go-sdk/v3/internal/scheme"
@@ -35,6 +37,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
"github.com/ydb-platform/ydb-go-sdk/v3/log"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
"github.com/ydb-platform/ydb-go-sdk/v3/ratelimiter"
"github.com/ydb-platform/ydb-go-sdk/v3/scheme"
"github.com/ydb-platform/ydb-go-sdk/v3/scripting"
@@ -47,7 +50,7 @@ import (
var _ Connection = (*Driver)(nil)
// Driver type provide access to YDB service clients
-type Driver struct { //nolint:maligned
+type Driver struct {
ctx context.Context // cancel while Driver.Close called.
ctxCancel context.CancelFunc
@@ -62,25 +65,28 @@ type Driver struct { //nolint:maligned
config *config.Config
options []config.Option
- discovery *internalDiscovery.Client
+ discovery *xsync.Once[*internalDiscovery.Client]
discoveryOptions []discoveryConfig.Option
- table *internalTable.Client
+ table *xsync.Once[*internalTable.Client]
tableOptions []tableConfig.Option
- scripting *internalScripting.Client
+ query *xsync.Once[*internalQuery.Client]
+ queryOptions []queryConfig.Option
+
+ scripting *xsync.Once[*internalScripting.Client]
scriptingOptions []scriptingConfig.Option
- scheme *internalScheme.Client
+ scheme *xsync.Once[*internalScheme.Client]
schemeOptions []schemeConfig.Option
- coordination *internalCoordination.Client
+ coordination *xsync.Once[*internalCoordination.Client]
coordinationOptions []coordinationConfig.Option
- ratelimiter *internalRatelimiter.Client
+ ratelimiter *xsync.Once[*internalRatelimiter.Client]
ratelimiterOptions []ratelimiterConfig.Option
- topic *topicclientinternal.Client
+ topic *xsync.Once[*topicclientinternal.Client]
topicOptions []topicoptions.TopicOption
databaseSQLOptions []xsql.ConnectorOption
@@ -109,7 +115,9 @@ func (d *Driver) trace() *trace.Driver {
//
//nolint:nonamedreturns
func (d *Driver) Close(ctx context.Context) (finalErr error) {
- onDone := trace.DriverOnClose(d.trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnClose(d.trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.(*Driver).Close"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -141,6 +149,7 @@ func (d *Driver) Close(ctx context.Context) (finalErr error) {
d.scheme.Close,
d.scripting.Close,
d.table.Close,
+ d.query.Close,
d.topic.Close,
d.balancer.Close,
d.pool.Release,
@@ -177,37 +186,46 @@ func (d *Driver) Secure() bool {
// Table returns table client
func (d *Driver) Table() table.Client {
- return d.table
+ return d.table.Get()
+}
+
+// Query returns query client
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+func (d *Driver) Query() query.Client {
+ return d.query.Get()
}
// Scheme returns scheme client
func (d *Driver) Scheme() scheme.Client {
- return d.scheme
+ return d.scheme.Get()
}
// Coordination returns coordination client
func (d *Driver) Coordination() coordination.Client {
- return d.coordination
+ return d.coordination.Get()
}
// Ratelimiter returns ratelimiter client
func (d *Driver) Ratelimiter() ratelimiter.Client {
- return d.ratelimiter
+ return d.ratelimiter.Get()
}
// Discovery returns discovery client
func (d *Driver) Discovery() discovery.Client {
- return d.discovery
+ return d.discovery.Get()
}
// Scripting returns scripting client
func (d *Driver) Scripting() scripting.Client {
- return d.scripting
+ return d.scripting.Get()
}
// Topic returns topic client
func (d *Driver) Topic() topic.Client {
- return d.topic
+ return d.topic.Get()
}
// Open connects to database by DSN and return driver runtime holder
@@ -232,7 +250,7 @@ func Open(ctx context.Context, dsn string, opts ...Option) (_ *Driver, err error
onDone := trace.DriverOnInit(
d.trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.Open"),
d.config.Endpoint(), d.config.Database(), d.config.Secure(),
)
defer func() {
@@ -268,7 +286,7 @@ func New(ctx context.Context, opts ...Option) (_ *Driver, err error) {
onDone := trace.DriverOnInit(
d.trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.New"),
d.config.Endpoint(), d.config.Database(), d.config.Secure(),
)
defer func() {
@@ -284,7 +302,7 @@ func New(ctx context.Context, opts ...Option) (_ *Driver, err error) {
//nolint:cyclop, nonamedreturns
func newConnectionFromOptions(ctx context.Context, opts ...Option) (_ *Driver, err error) {
- ctx, driverCtxCancel := xcontext.WithCancel(xcontext.WithoutDeadline(ctx))
+ ctx, driverCtxCancel := xcontext.WithCancel(xcontext.ValueOnly(ctx))
defer func() {
if err != nil {
driverCtxCancel()
@@ -332,6 +350,7 @@ func newConnectionFromOptions(ctx context.Context, opts ...Option) (_ *Driver, e
for _, opt := range []Option{
WithTraceDriver(log.Driver(d.logger, d.loggerDetails, d.loggerOpts...)), //nolint:contextcheck
WithTraceTable(log.Table(d.logger, d.loggerDetails, d.loggerOpts...)), //nolint:contextcheck
+ WithTraceQuery(log.Query(d.logger, d.loggerDetails, d.loggerOpts...)), //nolint:contextcheck
WithTraceScripting(log.Scripting(d.logger, d.loggerDetails, d.loggerOpts...)), //nolint:contextcheck
WithTraceScheme(log.Scheme(d.logger, d.loggerDetails, d.loggerOpts...)),
WithTraceCoordination(log.Coordination(d.logger, d.loggerDetails, d.loggerOpts...)),
@@ -383,122 +402,133 @@ func (d *Driver) connect(ctx context.Context) (err error) {
return xerrors.WithStackTrace(err)
}
- d.table, err = internalTable.New(ctx,
- d.balancer,
- tableConfig.New(
- append(
- // prepend common params from root config
- []tableConfig.Option{
- tableConfig.With(d.config.Common),
- },
- d.tableOptions...,
- )...,
- ),
- )
- if err != nil {
- return xerrors.WithStackTrace(err)
- }
+ d.table = xsync.OnceValue(func() *internalTable.Client {
+ return internalTable.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ tableConfig.New(
+ append(
+ // prepend common params from root config
+ []tableConfig.Option{
+ tableConfig.With(d.config.Common),
+ },
+ d.tableOptions...,
+ )...,
+ ),
+ )
+ })
- d.scheme, err = internalScheme.New(ctx,
- d.balancer,
- schemeConfig.New(
- append(
- // prepend common params from root config
- []schemeConfig.Option{
- schemeConfig.WithDatabaseName(d.Name()),
- schemeConfig.With(d.config.Common),
- },
- d.schemeOptions...,
- )...,
- ),
- )
+ d.query = xsync.OnceValue(func() *internalQuery.Client {
+ return internalQuery.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ queryConfig.New(
+ append(
+ // prepend common params from root config
+ []queryConfig.Option{
+ queryConfig.With(d.config.Common),
+ },
+ d.queryOptions...,
+ )...,
+ ),
+ )
+ })
if err != nil {
return xerrors.WithStackTrace(err)
}
- d.coordination, err = internalCoordination.New(ctx,
- d.balancer,
- coordinationConfig.New(
- append(
- // prepend common params from root config
- []coordinationConfig.Option{
- coordinationConfig.With(d.config.Common),
- },
- d.coordinationOptions...,
- )...,
- ),
- )
- if err != nil {
- return xerrors.WithStackTrace(err)
- }
+ d.scheme = xsync.OnceValue(func() *internalScheme.Client {
+ return internalScheme.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ schemeConfig.New(
+ append(
+ // prepend common params from root config
+ []schemeConfig.Option{
+ schemeConfig.WithDatabaseName(d.Name()),
+ schemeConfig.With(d.config.Common),
+ },
+ d.schemeOptions...,
+ )...,
+ ),
+ )
+ })
- d.ratelimiter, err = internalRatelimiter.New(ctx,
- d.balancer,
- ratelimiterConfig.New(
- append(
- // prepend common params from root config
- []ratelimiterConfig.Option{
- ratelimiterConfig.With(d.config.Common),
- },
- d.ratelimiterOptions...,
- )...,
- ),
- )
- if err != nil {
- return xerrors.WithStackTrace(err)
- }
+ d.coordination = xsync.OnceValue(func() *internalCoordination.Client {
+ return internalCoordination.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ coordinationConfig.New(
+ append(
+ // prepend common params from root config
+ []coordinationConfig.Option{
+ coordinationConfig.With(d.config.Common),
+ },
+ d.coordinationOptions...,
+ )...,
+ ),
+ )
+ })
- d.discovery, err = internalDiscovery.New(ctx,
- d.pool.Get(endpoint.New(d.config.Endpoint())),
- discoveryConfig.New(
- append(
- // prepend common params from root config
- []discoveryConfig.Option{
- discoveryConfig.With(d.config.Common),
- discoveryConfig.WithEndpoint(d.Endpoint()),
- discoveryConfig.WithDatabase(d.Name()),
- discoveryConfig.WithSecure(d.Secure()),
- discoveryConfig.WithMeta(d.config.Meta()),
- },
- d.discoveryOptions...,
- )...,
- ),
- )
- if err != nil {
- return xerrors.WithStackTrace(err)
- }
+ d.ratelimiter = xsync.OnceValue(func() *internalRatelimiter.Client {
+ return internalRatelimiter.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ ratelimiterConfig.New(
+ append(
+ // prepend common params from root config
+ []ratelimiterConfig.Option{
+ ratelimiterConfig.With(d.config.Common),
+ },
+ d.ratelimiterOptions...,
+ )...,
+ ),
+ )
+ })
- d.scripting, err = internalScripting.New(ctx,
- d.balancer,
- scriptingConfig.New(
+ d.discovery = xsync.OnceValue(func() *internalDiscovery.Client {
+ return internalDiscovery.New(xcontext.ValueOnly(ctx),
+ d.pool.Get(endpoint.New(d.config.Endpoint())),
+ discoveryConfig.New(
+ append(
+ // prepend common params from root config
+ []discoveryConfig.Option{
+ discoveryConfig.With(d.config.Common),
+ discoveryConfig.WithEndpoint(d.Endpoint()),
+ discoveryConfig.WithDatabase(d.Name()),
+ discoveryConfig.WithSecure(d.Secure()),
+ discoveryConfig.WithMeta(d.config.Meta()),
+ },
+ d.discoveryOptions...,
+ )...,
+ ),
+ )
+ })
+
+ d.scripting = xsync.OnceValue(func() *internalScripting.Client {
+ return internalScripting.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ scriptingConfig.New(
+ append(
+ // prepend common params from root config
+ []scriptingConfig.Option{
+ scriptingConfig.With(d.config.Common),
+ },
+ d.scriptingOptions...,
+ )...,
+ ),
+ )
+ })
+
+ d.topic = xsync.OnceValue(func() *topicclientinternal.Client {
+ return topicclientinternal.New(xcontext.ValueOnly(ctx),
+ d.balancer,
+ d.config.Credentials(),
append(
// prepend common params from root config
- []scriptingConfig.Option{
- scriptingConfig.With(d.config.Common),
+ []topicoptions.TopicOption{
+ topicoptions.WithOperationTimeout(d.config.OperationTimeout()),
+ topicoptions.WithOperationCancelAfter(d.config.OperationCancelAfter()),
},
- d.scriptingOptions...,
+ d.topicOptions...,
)...,
- ),
- )
- if err != nil {
- return xerrors.WithStackTrace(err)
- }
-
- d.topic, err = topicclientinternal.New(ctx,
- d.balancer,
- d.config.Credentials(),
- append(
- // prepend common params from root config
- []topicoptions.TopicOption{
- topicoptions.WithOperationTimeout(d.config.OperationTimeout()),
- topicoptions.WithOperationCancelAfter(d.config.OperationCancelAfter()),
- },
- d.topicOptions...,
- )...,
- )
- if err != nil {
- return xerrors.WithStackTrace(err)
- }
+ )
+ })
return nil
}
diff --git a/driver_string.go b/driver_string.go
index d2b5fd6f7..32b52fbc8 100644
--- a/driver_string.go
+++ b/driver_string.go
@@ -18,5 +18,6 @@ func (d *Driver) String() string {
fmt.Fprintf(buffer, ",Credentials:%v", c.String())
}
buffer.WriteByte('}')
+
return buffer.String()
}
diff --git a/driver_string_test.go b/driver_string_test.go
index 812a81e94..cc4e1cbe9 100644
--- a/driver_string_test.go
+++ b/driver_string_test.go
@@ -23,7 +23,7 @@ func TestDriver_String(t *testing.T) {
config.WithDatabase("local"),
config.WithSecure(false),
)},
- s: `Driver{Endpoint:"localhost",Database:"local",Secure:false,Credentials:Anonymous{From:"github.com/ydb-platform/ydb-go-sdk/v3/config.defaultConfig(defaults.go:88)"}}`, //nolint:lll
+ s: `Driver{Endpoint:"localhost",Database:"local",Secure:false,Credentials:Anonymous{From:"github.com/ydb-platform/ydb-go-sdk/v3/config.defaultConfig(defaults.go:90)"}}`, //nolint:lll
},
{
name: xtest.CurrentFileLine(),
@@ -32,7 +32,7 @@ func TestDriver_String(t *testing.T) {
config.WithDatabase("local"),
config.WithSecure(true),
)},
- s: `Driver{Endpoint:"localhost",Database:"local",Secure:true,Credentials:Anonymous{From:"github.com/ydb-platform/ydb-go-sdk/v3/config.defaultConfig(defaults.go:88)"}}`, //nolint:lll
+ s: `Driver{Endpoint:"localhost",Database:"local",Secure:true,Credentials:Anonymous{From:"github.com/ydb-platform/ydb-go-sdk/v3/config.defaultConfig(defaults.go:90)"}}`, //nolint:lll
},
{
name: xtest.CurrentFileLine(),
diff --git a/example_test.go b/example_test.go
index 3b06248e6..399411e68 100644
--- a/example_test.go
+++ b/example_test.go
@@ -3,6 +3,7 @@ package ydb_test
import (
"context"
"database/sql"
+ "errors"
"fmt"
"io"
"log"
@@ -14,6 +15,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/balancers"
"github.com/ydb-platform/ydb-go-sdk/v3/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
@@ -21,6 +23,69 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
)
+//nolint:testableexamples, nonamedreturns
+func Example_query() {
+ ctx := context.TODO()
+ db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer db.Close(ctx) // cleanup resources
+
+ err = db.Query().Do( // Do retry operation on errors with best effort
+ ctx, // context manage exiting from Do
+ func(ctx context.Context, s query.Session) (err error) { // retry operation
+ _, res, err := s.Execute(ctx,
+ `SELECT $id as myId, $str as myStr`,
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$id").Uint64(42).
+ Param("$str").Text("my string").
+ Build(),
+ ),
+ )
+ if err != nil {
+ return err // for auto-retry with driver
+ }
+ defer func() { _ = res.Close(ctx) }() // cleanup resources
+ for { // iterate over result sets
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ for { // iterate over rows
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ type myStruct struct {
+ id uint64 `sql:"id"`
+ str string `sql:"myStr"`
+ }
+ var s myStruct
+ if err = row.ScanStruct(&s); err != nil {
+ return err // generally scan error not retryable, return it for driver check error
+ }
+ }
+ }
+
+ return res.Err() // return finally result error for auto-retry with driver
+ },
+ query.WithIdempotent(),
+ )
+ if err != nil {
+ log.Printf("unexpected error: %v", err)
+ }
+}
+
//nolint:testableexamples, nonamedreturns
func Example_table() {
ctx := context.TODO()
diff --git a/examples/auth/environ/main.go b/examples/auth/environ/main.go
index 86dd1b01c..0ab5d2228 100644
--- a/examples/auth/environ/main.go
+++ b/examples/auth/environ/main.go
@@ -6,7 +6,6 @@ import (
"os"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
)
diff --git a/examples/auth/metadata_credentials/main.go b/examples/auth/metadata_credentials/main.go
index 00e55ffc2..073025b53 100644
--- a/examples/auth/metadata_credentials/main.go
+++ b/examples/auth/metadata_credentials/main.go
@@ -6,9 +6,8 @@ import (
"fmt"
"os"
- yc "github.com/ydb-platform/ydb-go-yc"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ yc "github.com/ydb-platform/ydb-go-yc"
)
var dsn string
diff --git a/examples/auth/service_account_credentials/main.go b/examples/auth/service_account_credentials/main.go
index 879ea9ba7..160d488b8 100644
--- a/examples/auth/service_account_credentials/main.go
+++ b/examples/auth/service_account_credentials/main.go
@@ -6,9 +6,8 @@ import (
"fmt"
"os"
- yc "github.com/ydb-platform/ydb-go-yc"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ yc "github.com/ydb-platform/ydb-go-yc"
)
var (
diff --git a/examples/basic/database_sql/data.go b/examples/basic/database_sql/data.go
index 279c895be..5b373b7a3 100644
--- a/examples/basic/database_sql/data.go
+++ b/examples/basic/database_sql/data.go
@@ -8,7 +8,6 @@ import (
"time"
"github.com/google/uuid"
-
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
@@ -19,6 +18,7 @@ func seriesData(id string, released time.Time, title, info, comment string) type
} else {
commentv = types.OptionalValue(types.TextValue(comment))
}
+
return types.StructValue(
types.StructFieldValue("series_id", types.BytesValueFromString(id)),
types.StructFieldValue("release_date", types.DateValueFromTime(released)),
@@ -60,6 +60,7 @@ func getData() (series, seasons, episodes []types.Value) {
seasons = append(seasons, seasonsData...)
episodes = append(episodes, episodesData...)
}
+
return
}
@@ -115,6 +116,7 @@ func getDataForITCrowd(seriesID string) (series types.Value, seasons, episodes [
episodes = append(episodes, episodeData(seriesID, seasonID, uuid.New().String(), title, date))
}
}
+
return series, seasons, episodes
}
@@ -194,6 +196,7 @@ func getDataForSiliconValley(seriesID string) (series types.Value, seasons, epis
episodes = append(episodes, episodeData(seriesID, seasonID, uuid.New().String(), title, date))
}
}
+
return series, seasons, episodes
}
@@ -204,5 +207,6 @@ func date(date string) time.Time {
if err != nil {
panic(err)
}
+
return t
}
diff --git a/examples/basic/database_sql/main.go b/examples/basic/database_sql/main.go
index 0c44ce7b9..e4c31bfe9 100644
--- a/examples/basic/database_sql/main.go
+++ b/examples/basic/database_sql/main.go
@@ -9,7 +9,6 @@ import (
"time"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
)
diff --git a/examples/basic/database_sql/series.go b/examples/basic/database_sql/series.go
index d76904e50..28c39a50d 100644
--- a/examples/basic/database_sql/series.go
+++ b/examples/basic/database_sql/series.go
@@ -30,6 +30,7 @@ func selectDefault(ctx context.Context, db *sql.DB) (err error) {
return err
}
log.Printf("AST = %s\n\nPlan = %s", ast, plan)
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
@@ -61,11 +62,13 @@ func selectDefault(ctx context.Context, db *sql.DB) (err error) {
*id, *title, releaseDate.Format("2006-01-02"),
)
}
+
return rows.Err()
}, retry.WithIdempotent(true))
if err != nil {
return fmt.Errorf("execute data query failed: %w", err)
}
+
return nil
}
@@ -154,11 +157,13 @@ func selectScan(ctx context.Context, db *sql.DB) (err error) {
episodeID, title, firstAired.Format("2006-01-02"),
)
}
+
return rows.Err()
}, retry.WithIdempotent(true))
if err != nil {
return fmt.Errorf("scan query failed: %w", err)
}
+
return nil
}
@@ -201,11 +206,13 @@ func fillTablesWithData(ctx context.Context, db *sql.DB) (err error) {
); err != nil {
return err
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
return fmt.Errorf("upsert query failed: %w", err)
}
+
return nil
}
@@ -232,8 +239,10 @@ func prepareSchema(ctx context.Context, db *sql.DB) (err error) {
)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "create series table failed: %v", err)
+
return err
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
@@ -263,8 +272,10 @@ func prepareSchema(ctx context.Context, db *sql.DB) (err error) {
)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "create seasons table failed: %v\n", err)
+
return err
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
@@ -296,13 +307,16 @@ func prepareSchema(ctx context.Context, db *sql.DB) (err error) {
)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "create episodes table failed: %v\n", err)
+
return err
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
return fmt.Errorf("create table failed: %w", err)
}
+
return nil
}
@@ -326,5 +340,6 @@ func dropTableIfExists(ctx context.Context, cc *sql.Conn, tableName string) erro
if err != nil {
return fmt.Errorf("drop table failed: %w", err)
}
+
return nil
}
diff --git a/examples/basic/gorm/data.go b/examples/basic/gorm/data.go
index 6d92ad170..b5b72f269 100644
--- a/examples/basic/gorm/data.go
+++ b/examples/basic/gorm/data.go
@@ -373,5 +373,6 @@ func date(date string) time.Time {
if err != nil {
panic(err)
}
+
return t
}
diff --git a/examples/basic/gorm/main.go b/examples/basic/gorm/main.go
index 6affba9e0..725032216 100644
--- a/examples/basic/gorm/main.go
+++ b/examples/basic/gorm/main.go
@@ -85,6 +85,7 @@ func prepareScheme(db *gorm.DB) error {
); err != nil {
return err
}
+
return db.AutoMigrate(
&Series{},
&Season{},
@@ -123,6 +124,7 @@ func readAll(db *gorm.DB) error {
}
}
}
+
return nil
}
@@ -161,5 +163,6 @@ func findEpisodesByTitle(db *gorm.DB, fragment string) error {
episodes[i].ID, episodes[i].AirDate.Format(dateISO8601), episodes[i].Title,
)
}
+
return nil
}
diff --git a/examples/basic/gorm/models.go b/examples/basic/gorm/models.go
index c96edc7ee..8b2b05d64 100644
--- a/examples/basic/gorm/models.go
+++ b/examples/basic/gorm/models.go
@@ -26,6 +26,7 @@ func (s *Series) BeforeCreate(_ *gorm.DB) (err error) {
for i := range s.Seasons {
s.Seasons[i].SeriesID = s.ID
}
+
return
}
@@ -48,6 +49,7 @@ func (s *Season) BeforeCreate(_ *gorm.DB) (err error) {
for i := range s.Episodes {
s.Episodes[i].SeasonID = s.ID
}
+
return
}
@@ -64,5 +66,6 @@ func (e *Episode) BeforeCreate(_ *gorm.DB) (err error) {
return err
}
e.ID = id.String()
+
return
}
diff --git a/examples/basic/native/README.md b/examples/basic/native/query/README.md
similarity index 100%
rename from examples/basic/native/README.md
rename to examples/basic/native/query/README.md
diff --git a/examples/basic/native/query/data.go b/examples/basic/native/query/data.go
new file mode 100644
index 000000000..cbdbde95c
--- /dev/null
+++ b/examples/basic/native/query/data.go
@@ -0,0 +1,208 @@
+package main
+
+import (
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
+)
+
+func seriesData(id string, released time.Time, title, info, comment string) types.Value {
+ var commentv types.Value
+ if comment == "" {
+ commentv = types.NullValue(types.TypeUTF8)
+ } else {
+ commentv = types.OptionalValue(types.TextValue(comment))
+ }
+
+ return types.StructValue(
+ types.StructFieldValue("series_id", types.BytesValueFromString(id)),
+ types.StructFieldValue("release_date", types.DateValueFromTime(released)),
+ types.StructFieldValue("title", types.TextValue(title)),
+ types.StructFieldValue("series_info", types.TextValue(info)),
+ types.StructFieldValue("comment", commentv),
+ )
+}
+
+func seasonData(seriesID, seasonID, title string, first, last time.Time) types.Value {
+ return types.StructValue(
+ types.StructFieldValue("series_id", types.BytesValueFromString(seriesID)),
+ types.StructFieldValue("season_id", types.BytesValueFromString(seasonID)),
+ types.StructFieldValue("title", types.TextValue(title)),
+ types.StructFieldValue("first_aired", types.DateValueFromTime(first)),
+ types.StructFieldValue("last_aired", types.DateValueFromTime(last)),
+ )
+}
+
+func episodeData(seriesID, seasonID, episodeID, title string, date time.Time) types.Value {
+ return types.StructValue(
+ types.StructFieldValue("series_id", types.BytesValueFromString(seriesID)),
+ types.StructFieldValue("season_id", types.BytesValueFromString(seasonID)),
+ types.StructFieldValue("episode_id", types.BytesValueFromString(episodeID)),
+ types.StructFieldValue("title", types.TextValue(title)),
+ types.StructFieldValue("air_date", types.DateValueFromTime(date)),
+ )
+}
+
+func getData() (series, seasons, episodes []types.Value) {
+ for seriesID, fill := range map[string]func(seriesID string) (
+ seriesData types.Value, seasons []types.Value, episodes []types.Value,
+ ){
+ uuid.New().String(): getDataForITCrowd,
+ uuid.New().String(): getDataForSiliconValley,
+ } {
+ seriesData, seasonsData, episodesData := fill(seriesID)
+ series = append(series, seriesData)
+ seasons = append(seasons, seasonsData...)
+ episodes = append(episodes, episodesData...)
+ }
+
+ return
+}
+
+func getDataForITCrowd(seriesID string) (series types.Value, seasons, episodes []types.Value) {
+ series = seriesData(
+ seriesID, date("2006-02-03"), "IT Crowd", ""+
+ "The IT Crowd is a British sitcom produced by Channel 4, written by Graham Linehan, produced by "+
+ "Ash Atalla and starring Chris O'Dowd, Richard Ayoade, Katherine Parkinson, and Matt Berry.",
+ "", // NULL comment.
+ )
+ for _, season := range []struct { //nolint:gocritic
+ title string
+ first time.Time
+ last time.Time
+ episodes map[string]time.Time
+ }{
+ {"Season 1", date("2006-02-03"), date("2006-03-03"), map[string]time.Time{
+ "Yesterday's Jam": date("2006-02-03"),
+ "Calamity Jen": date("2006-02-03"),
+ "Fifty-Fifty": date("2006-02-10"),
+ "The Red Door": date("2006-02-17"),
+ "The Haunting of Bill Crouse": date("2006-02-24"),
+ "Aunt Irma Visits": date("2006-03-03"),
+ }},
+ {"Season 2", date("2007-08-24"), date("2007-09-28"), map[string]time.Time{
+ "The Work Outing": date("2006-08-24"),
+ "Return of the Golden Child": date("2007-08-31"),
+ "Moss and the German": date("2007-09-07"),
+ "The Dinner Party": date("2007-09-14"),
+ "Smoke and Mirrors": date("2007-09-21"),
+ "Men Without Women": date("2007-09-28"),
+ }},
+ {"Season 3", date("2008-11-21"), date("2008-12-26"), map[string]time.Time{
+ "From Hell": date("2008-11-21"),
+ "Are We Not Men?": date("2008-11-28"),
+ "Tramps Like Us": date("2008-12-05"),
+ "The Speech": date("2008-12-12"),
+ "Friendface": date("2008-12-19"),
+ "Calendar Geeks": date("2008-12-26"),
+ }},
+ {"Season 4", date("2010-06-25"), date("2010-07-30"), map[string]time.Time{
+ "Jen The Fredo": date("2010-06-25"),
+ "The Final Countdown": date("2010-07-02"),
+ "Something Happened": date("2010-07-09"),
+ "Italian For Beginners": date("2010-07-16"),
+ "Bad Boys": date("2010-07-23"),
+ "Reynholm vs Reynholm": date("2010-07-30"),
+ }},
+ } {
+ seasonID := uuid.New().String()
+ seasons = append(seasons, seasonData(seriesID, seasonID, season.title, season.first, season.last))
+ for title, date := range season.episodes {
+ episodes = append(episodes, episodeData(seriesID, seasonID, uuid.New().String(), title, date))
+ }
+ }
+
+ return series, seasons, episodes
+}
+
+func getDataForSiliconValley(seriesID string) (series types.Value, seasons, episodes []types.Value) {
+ series = seriesData(
+ seriesID, date("2014-04-06"), "Silicon Valley", ""+
+ "Silicon Valley is an American comedy television series created by Mike Judge, John Altschuler and "+
+ "Dave Krinsky. The series focuses on five young men who founded a startup company in Silicon Valley.",
+ "Some comment here",
+ )
+ for _, season := range []struct { //nolint:gocritic
+ title string
+ first time.Time
+ last time.Time
+ episodes map[string]time.Time
+ }{
+ {"Season 1", date("2006-02-03"), date("2006-03-03"), map[string]time.Time{
+ "Minimum Viable Product": date("2014-04-06"),
+ "The Cap Table": date("2014-04-13"),
+ "Articles of Incorporation": date("2014-04-20"),
+ "Fiduciary Duties": date("2014-04-27"),
+ "Signaling Risk": date("2014-05-04"),
+ "Third Party Insourcing": date("2014-05-11"),
+ "Proof of Concept": date("2014-05-18"),
+ "Optimal Tip-to-Tip Efficiency": date("2014-06-01"),
+ }},
+ {"Season 2", date("2007-08-24"), date("2007-09-28"), map[string]time.Time{
+ "Sand Hill Shuffle": date("2015-04-12"),
+ "Runaway Devaluation": date("2015-04-19"),
+ "Bad Money": date("2015-04-26"),
+ "The Lady": date("2015-05-03"),
+ "Server Space": date("2015-05-10"),
+ "Homicide": date("2015-05-17"),
+ "Adult Content": date("2015-05-24"),
+ "White Hat/Black Hat": date("2015-05-31"),
+ "Binding Arbitration": date("2015-06-07"),
+ "Two Days of the Condor": date("2015-06-14"),
+ }},
+ {"Season 3", date("2008-11-21"), date("2008-12-26"), map[string]time.Time{
+ "Founder Friendly": date("2016-04-24"),
+ "Two in the Box": date("2016-05-01"),
+ "Meinertzhagen's Haversack": date("2016-05-08"),
+ "Maleant Data Systems Solutions": date("2016-05-15"),
+ "The Empty Chair": date("2016-05-22"),
+ "Bachmanity Insanity": date("2016-05-29"),
+ "To Build a Better Beta": date("2016-06-05"),
+ "Bachman's Earnings Over-Ride": date("2016-06-12"),
+ "Daily Active Users": date("2016-06-19"),
+ "The Uptick": date("2016-06-26"),
+ }},
+ {"Season 4", date("2010-06-25"), date("2010-07-30"), map[string]time.Time{
+ "Success Failure": date("2017-04-23"),
+ "Terms of Service": date("2017-04-30"),
+ "Intellectual Property": date("2017-05-07"),
+ "Teambuilding Exercise": date("2017-05-14"),
+ "The Blood Boy": date("2017-05-21"),
+ "Customer Service": date("2017-05-28"),
+ "The Patent Troll": date("2017-06-04"),
+ "The Keenan Vortex": date("2017-06-11"),
+ "Hooli-Con": date("2017-06-18"),
+ "Server Error": date("2017-06-25"),
+ }},
+ {"Season 5", date("2018-03-25"), date("2018-05-13"), map[string]time.Time{
+ "Grow Fast or Die Slow": date("2018-03-25"),
+ "Reorientation": date("2018-04-01"),
+ "Chief Operating Officer": date("2018-04-08"),
+ "Tech Evangelist": date("2018-04-15"),
+ "Facial Recognition": date("2018-04-22"),
+ "Artificial Emotional Intelligence": date("2018-04-29"),
+ "Initial Coin Offering": date("2018-05-06"),
+ "Fifty-One Percent": date("2018-05-13"),
+ }},
+ } {
+ seasonID := uuid.New().String()
+ seasons = append(seasons, seasonData(seriesID, seasonID, season.title, season.first, season.last))
+ for title, date := range season.episodes {
+ episodes = append(episodes, episodeData(seriesID, seasonID, uuid.New().String(), title, date))
+ }
+ }
+
+ return series, seasons, episodes
+}
+
+const dateISO8601 = "2006-01-02"
+
+func date(date string) time.Time {
+ t, err := time.Parse(dateISO8601, date)
+ if err != nil {
+ panic(err)
+ }
+
+ return t
+}
diff --git a/examples/basic/native/query/main.go b/examples/basic/native/query/main.go
new file mode 100644
index 000000000..bf13c8f2f
--- /dev/null
+++ b/examples/basic/native/query/main.go
@@ -0,0 +1,87 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "path"
+ "strings"
+ "time"
+
+ environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
+ ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/sugar"
+)
+
+func isYdbVersionHaveQueryService() error {
+ minYdbVersion := strings.Split("24.1", ".")
+ ydbVersion := strings.Split(os.Getenv("YDB_VERSION"), ".")
+ for i, component := range ydbVersion {
+ if i < len(minYdbVersion) {
+ if r := strings.Compare(component, minYdbVersion[i]); r < 0 {
+ return fmt.Errorf("example '%s' run on minimal YDB version '%v', but current version is '%s'",
+ os.Args[0],
+ strings.Join(minYdbVersion, "."),
+ func() string {
+ if len(ydbVersion) > 0 && ydbVersion[0] != "" {
+ return strings.Join(ydbVersion, ".")
+ }
+
+ return "undefined"
+ }(),
+ )
+ } else if r > 0 {
+ return nil
+ }
+ }
+ }
+
+ return nil
+}
+
+func main() {
+ if err := isYdbVersionHaveQueryService(); err != nil {
+ fmt.Println(err.Error())
+
+ return
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ dsn, exists := os.LookupEnv("YDB_CONNECTION_STRING")
+ if !exists {
+ panic("YDB_CONNECTION_STRING environment variable not defined")
+ }
+
+ db, err := ydb.Open(ctx,
+ dsn,
+ environ.WithEnvironCredentials(ctx),
+ )
+ if err != nil {
+ panic(fmt.Errorf("connect error: %w", err))
+ }
+ defer func() { _ = db.Close(ctx) }()
+
+ prefix := path.Join(db.Name(), "native/query")
+
+ err = sugar.RemoveRecursive(ctx, db, prefix)
+ if err != nil {
+ panic(err)
+ }
+
+ err = createTables(ctx, db.Query(), prefix)
+ if err != nil {
+ panic(fmt.Errorf("create tables error: %w", err))
+ }
+
+ err = fillTablesWithData(ctx, db.Query(), prefix)
+ if err != nil {
+ panic(fmt.Errorf("fill tables with data error: %w", err))
+ }
+
+ err = read(ctx, db.Query(), prefix)
+ if err != nil {
+ panic(fmt.Errorf("select simple error: %w", err))
+ }
+}
diff --git a/examples/basic/native/query/series.go b/examples/basic/native/query/series.go
new file mode 100644
index 000000000..6c66d3912
--- /dev/null
+++ b/examples/basic/native/query/series.go
@@ -0,0 +1,202 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "path"
+ "time"
+
+ ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+)
+
+func read(ctx context.Context, c query.Client, prefix string) error {
+ return c.Do(ctx,
+ func(ctx context.Context, s query.Session) (err error) {
+ _, result, err := s.Execute(ctx, fmt.Sprintf(`
+ PRAGMA TablePathPrefix("%s");
+ DECLARE $seriesID AS Uint64;
+ SELECT
+ series_id,
+ title,
+ release_date
+ FROM
+ series
+ `, prefix),
+ query.WithTxControl(query.TxControl(query.BeginTx(query.WithOnlineReadOnly()))),
+ query.WithStatsMode(query.StatsModeBasic),
+ )
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ _ = result.Close(ctx)
+ }()
+
+ for {
+ resultSet, err := result.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return result.Err()
+ }
+
+ return err
+ }
+ for {
+ row, err := resultSet.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return result.Err()
+ }
+
+ return err
+ }
+
+ var info struct {
+ SeriesID string `sql:"series_id"`
+ Title string `sql:"title"`
+ ReleaseDate time.Time `sql:"release_date"`
+ }
+ err = row.ScanStruct(&info)
+ if err != nil {
+ return err
+ }
+ log.Printf("%+v", info)
+ }
+ }
+ },
+ )
+}
+
+func fillTablesWithData(ctx context.Context, c query.Client, prefix string) error {
+ series, seasons, episodes := getData()
+
+ return c.Do(ctx,
+ func(ctx context.Context, s query.Session) (err error) {
+ _, _, err = s.Execute(ctx,
+ fmt.Sprintf(`
+ PRAGMA TablePathPrefix("%s");
+
+ DECLARE $seriesData AS List>>;
+
+ DECLARE $seasonsData AS List>;
+
+ DECLARE $episodesData AS List>;
+
+ REPLACE INTO series
+ SELECT
+ series_id,
+ title,
+ series_info,
+ release_date,
+ comment
+ FROM AS_TABLE($seriesData);
+
+ REPLACE INTO seasons
+ SELECT
+ series_id,
+ season_id,
+ title,
+ first_aired,
+ last_aired
+ FROM AS_TABLE($seasonsData);
+
+ REPLACE INTO episodes
+ SELECT
+ series_id,
+ season_id,
+ episode_id,
+ title,
+ air_date
+ FROM AS_TABLE($episodesData);
+ `, prefix),
+ query.WithParameters(ydb.ParamsBuilder().
+ Param("$seriesData").BeginList().AddItems(series...).EndList().
+ Param("$seasonsData").BeginList().AddItems(seasons...).EndList().
+ Param("$episodesData").BeginList().AddItems(episodes...).EndList().
+ Build(),
+ ),
+ )
+
+ return err
+ },
+ )
+}
+
+func createTables(ctx context.Context, c query.Client, prefix string) error {
+ return c.Do(ctx,
+ func(ctx context.Context, s query.Session) error {
+ _, _, err := s.Execute(ctx, fmt.Sprintf(`
+ CREATE TABLE IF NOT EXISTS %s (
+ series_id Bytes,
+ title Text,
+ series_info Text,
+ release_date Date,
+ comment Text,
+
+ PRIMARY KEY(series_id)
+ )
+ `, "`"+path.Join(prefix, "series")+"`"),
+ query.WithTxControl(query.NoTx()),
+ )
+ if err != nil {
+ return err
+ }
+
+ _, _, err = s.Execute(ctx, fmt.Sprintf(`
+ CREATE TABLE IF NOT EXISTS %s (
+ series_id Bytes,
+ season_id Bytes,
+ title Text,
+ first_aired Date,
+ last_aired Date,
+
+ PRIMARY KEY(series_id,season_id)
+ )
+ `, "`"+path.Join(prefix, "seasons")+"`"),
+ query.WithTxControl(query.NoTx()),
+ )
+ if err != nil {
+ return err
+ }
+
+ _, _, err = s.Execute(ctx, fmt.Sprintf(`
+ CREATE TABLE IF NOT EXISTS %s (
+ series_id Bytes,
+ season_id Bytes,
+ episode_id Bytes,
+ title Text,
+ air_date Date,
+
+ PRIMARY KEY(series_id,season_id,episode_id)
+ )
+ `, "`"+path.Join(prefix, "episodes")+"`"),
+ query.WithTxControl(query.NoTx()),
+ )
+ if err != nil {
+ return err
+ }
+
+ return nil
+ },
+ )
+}
diff --git a/examples/basic/native/table/README.md b/examples/basic/native/table/README.md
new file mode 100644
index 000000000..1f2543f35
--- /dev/null
+++ b/examples/basic/native/table/README.md
@@ -0,0 +1,8 @@
+# Basic example via native driver
+
+Basic example demonstrates the possibilities of `YDB`:
+ - create/drop/describe tables
+ - upsert data
+ - select with data query (request-response API)
+ - select with scan query (streaming API)
+ - read table (streaming API)
\ No newline at end of file
diff --git a/examples/basic/native/data.go b/examples/basic/native/table/data.go
similarity index 99%
rename from examples/basic/native/data.go
rename to examples/basic/native/table/data.go
index cc8e7f3fc..cc4b12547 100644
--- a/examples/basic/native/data.go
+++ b/examples/basic/native/table/data.go
@@ -13,6 +13,7 @@ func seriesData(id uint64, released time.Time, title, info, comment string) type
} else {
commentv = types.OptionalValue(types.TextValue(comment))
}
+
return types.StructValue(
types.StructFieldValue("series_id", types.Uint64Value(id)),
types.StructFieldValue("release_date", types.DateValueFromTime(released)),
@@ -155,5 +156,6 @@ func days(date string) time.Time {
if err != nil {
panic(err)
}
+
return t
}
diff --git a/examples/basic/native/main.go b/examples/basic/native/table/main.go
similarity index 97%
rename from examples/basic/native/main.go
rename to examples/basic/native/table/main.go
index e2cfd23df..b624c4f12 100644
--- a/examples/basic/native/main.go
+++ b/examples/basic/native/table/main.go
@@ -8,7 +8,6 @@ import (
"time"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
)
@@ -31,7 +30,7 @@ func main() {
}
defer func() { _ = db.Close(ctx) }()
- prefix := path.Join(db.Name(), "native")
+ prefix := path.Join(db.Name(), "native/table")
err = sugar.RemoveRecursive(ctx, db, prefix)
if err != nil {
diff --git a/examples/basic/native/series.go b/examples/basic/native/table/series.go
similarity index 64%
rename from examples/basic/native/series.go
rename to examples/basic/native/table/series.go
index a9e267aab..2a5bc91b4 100644
--- a/examples/basic/native/series.go
+++ b/examples/basic/native/table/series.go
@@ -9,7 +9,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/result"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
@@ -70,126 +69,127 @@ SELECT
FROM AS_TABLE($episodesData);
`))
-func readTable(ctx context.Context, c table.Client, path string) (err error) {
- var res result.StreamResult
- err = c.Do(ctx,
- func(ctx context.Context, s table.Session) (err error) {
- res, err = s.StreamReadTable(ctx, path,
+func readTable(ctx context.Context, c table.Client, path string) error {
+ return c.Do(ctx,
+ func(ctx context.Context, s table.Session) error {
+ res, err := s.StreamReadTable(ctx, path,
options.ReadOrdered(),
options.ReadColumn("series_id"),
options.ReadColumn("title"),
options.ReadColumn("release_date"),
)
- return
- },
- )
- if err != nil {
- return err
- }
- defer func() {
- _ = res.Close()
- }()
- log.Printf("> read_table:")
- var (
- id *uint64
- title *string
- date *uint64
- )
- for res.NextResultSet(ctx) {
- for res.NextRow() {
- err = res.ScanNamed(
- named.Optional("series_id", &id),
- named.Optional("title", &title),
- named.Optional("release_date", &date),
- )
if err != nil {
return err
}
- log.Printf("# %d %s %d", *id, *title, *date)
- }
- }
- if err := res.Err(); err != nil {
- return err
- }
- if stats := res.Stats(); stats != nil {
- for i := 0; ; i++ {
- phase, ok := stats.NextPhase()
- if !ok {
- break
- }
- log.Printf(
- "# phase #%d: took %s",
- i, phase.Duration(),
+
+ defer func() {
+ _ = res.Close()
+ }()
+
+ log.Printf("> read_table:")
+
+ var (
+ id *uint64
+ title *string
+ date *uint64
)
- for {
- tbl, ok := phase.NextTableAccess()
- if !ok {
- break
+
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ err = res.ScanNamed(
+ named.Optional("series_id", &id),
+ named.Optional("title", &title),
+ named.Optional("release_date", &date),
+ )
+ if err != nil {
+ return err
+ }
+ log.Printf("# %d %s %d", *id, *title, *date)
+ }
+ }
+ if err := res.Err(); err != nil {
+ return err
+ }
+ if stats := res.Stats(); stats != nil {
+ for i := 0; ; i++ {
+ phase, ok := stats.NextPhase()
+ if !ok {
+ break
+ }
+ log.Printf(
+ "# phase #%d: took %s",
+ i, phase.Duration(),
+ )
+ for {
+ tbl, ok := phase.NextTableAccess()
+ if !ok {
+ break
+ }
+ log.Printf(
+ "# accessed %s: read=(%drows, %dbytes)",
+ tbl.Name, tbl.Reads.Rows, tbl.Reads.Bytes,
+ )
+ }
}
- log.Printf(
- "# accessed %s: read=(%drows, %dbytes)",
- tbl.Name, tbl.Reads.Rows, tbl.Reads.Bytes,
- )
}
- }
- }
- return res.Err()
+ return res.Err()
+ },
+ )
}
-func describeTableOptions(ctx context.Context, c table.Client) (err error) {
- var desc options.TableOptionsDescription
- err = c.Do(ctx,
+func describeTableOptions(ctx context.Context, c table.Client) error {
+ return c.Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
- desc, err = s.DescribeTableOptions(ctx)
- return
- },
- )
- if err != nil {
- return err
- }
- log.Println("> describe_table_options:")
+ desc, err := s.DescribeTableOptions(ctx)
+ if err != nil {
+ return err
+ }
- for i := range desc.TableProfilePresets {
- log.Printf("TableProfilePresets: %d/%d: %+v", i+1,
- len(desc.TableProfilePresets), desc.TableProfilePresets[i],
- )
- }
- for i := range desc.StoragePolicyPresets {
- log.Printf("StoragePolicyPresets: %d/%d: %+v", i+1,
- len(desc.StoragePolicyPresets), desc.StoragePolicyPresets[i],
- )
- }
- for i := range desc.CompactionPolicyPresets {
- log.Printf("CompactionPolicyPresets: %d/%d: %+v", i+1,
- len(desc.CompactionPolicyPresets), desc.CompactionPolicyPresets[i],
- )
- }
- for i := range desc.PartitioningPolicyPresets {
- log.Printf("PartitioningPolicyPresets: %d/%d: %+v", i+1,
- len(desc.PartitioningPolicyPresets), desc.PartitioningPolicyPresets[i],
- )
- }
- for i := range desc.ExecutionPolicyPresets {
- log.Printf("ExecutionPolicyPresets: %d/%d: %+v", i+1,
- len(desc.ExecutionPolicyPresets), desc.ExecutionPolicyPresets[i],
- )
- }
- for i := range desc.ReplicationPolicyPresets {
- log.Printf("ReplicationPolicyPresets: %d/%d: %+v", i+1,
- len(desc.ReplicationPolicyPresets), desc.ReplicationPolicyPresets[i],
- )
- }
- for i := range desc.CachingPolicyPresets {
- log.Printf("CachingPolicyPresets: %d/%d: %+v", i+1,
- len(desc.CachingPolicyPresets), desc.CachingPolicyPresets[i],
- )
- }
+ log.Println("> describe_table_options:")
+
+ for i := range desc.TableProfilePresets {
+ log.Printf("TableProfilePresets: %d/%d: %+v", i+1,
+ len(desc.TableProfilePresets), desc.TableProfilePresets[i],
+ )
+ }
+ for i := range desc.StoragePolicyPresets {
+ log.Printf("StoragePolicyPresets: %d/%d: %+v", i+1,
+ len(desc.StoragePolicyPresets), desc.StoragePolicyPresets[i],
+ )
+ }
+ for i := range desc.CompactionPolicyPresets {
+ log.Printf("CompactionPolicyPresets: %d/%d: %+v", i+1,
+ len(desc.CompactionPolicyPresets), desc.CompactionPolicyPresets[i],
+ )
+ }
+ for i := range desc.PartitioningPolicyPresets {
+ log.Printf("PartitioningPolicyPresets: %d/%d: %+v", i+1,
+ len(desc.PartitioningPolicyPresets), desc.PartitioningPolicyPresets[i],
+ )
+ }
+ for i := range desc.ExecutionPolicyPresets {
+ log.Printf("ExecutionPolicyPresets: %d/%d: %+v", i+1,
+ len(desc.ExecutionPolicyPresets), desc.ExecutionPolicyPresets[i],
+ )
+ }
+ for i := range desc.ReplicationPolicyPresets {
+ log.Printf("ReplicationPolicyPresets: %d/%d: %+v", i+1,
+ len(desc.ReplicationPolicyPresets), desc.ReplicationPolicyPresets[i],
+ )
+ }
+ for i := range desc.CachingPolicyPresets {
+ log.Printf("CachingPolicyPresets: %d/%d: %+v", i+1,
+ len(desc.CachingPolicyPresets), desc.CachingPolicyPresets[i],
+ )
+ }
- return nil
+ return nil
+ },
+ )
}
-func selectSimple(ctx context.Context, c table.Client, prefix string) (err error) {
+func selectSimple(ctx context.Context, c table.Client, prefix string) error {
query := render(
template.Must(template.New("").Parse(`
PRAGMA TablePathPrefix("{{ .TablePathPrefix }}");
@@ -218,51 +218,51 @@ func selectSimple(ctx context.Context, c table.Client, prefix string) (err error
),
table.CommitTx(),
)
- var res result.Result
- err = c.Do(ctx,
- func(ctx context.Context, s table.Session) (err error) {
- _, res, err = s.Execute(ctx, readTx, query,
+
+ return c.Do(ctx,
+ func(ctx context.Context, s table.Session) error {
+ _, res, err := s.Execute(ctx, readTx, query,
table.NewQueryParameters(
table.ValueParam("$seriesID", types.Uint64Value(1)),
),
options.WithCollectStatsModeBasic(),
)
- return
- },
- )
- if err != nil {
- return err
- }
-
- defer func() {
- _ = res.Close()
- }()
-
- var (
- id *uint64
- title *string
- date *[]byte
- )
- for res.NextResultSet(ctx) {
- for res.NextRow() {
- err = res.ScanNamed(
- named.Optional("series_id", &id),
- named.Optional("title", &title),
- named.Optional("release_date", &date),
- )
if err != nil {
return err
}
- log.Printf(
- "> select_simple_transaction: %d %s %s",
- *id, *title, *date,
+
+ defer func() {
+ _ = res.Close()
+ }()
+
+ var (
+ id *uint64
+ title *string
+ date *[]byte
)
- }
- }
- return res.Err()
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ err = res.ScanNamed(
+ named.Optional("series_id", &id),
+ named.Optional("title", &title),
+ named.Optional("release_date", &date),
+ )
+ if err != nil {
+ return err
+ }
+ log.Printf(
+ "> select_simple_transaction: %d %s %s",
+ *id, *title, *date,
+ )
+ }
+ }
+
+ return res.Err()
+ },
+ )
}
-func scanQuerySelect(ctx context.Context, c table.Client, prefix string) (err error) {
+func scanQuerySelect(ctx context.Context, c table.Client, prefix string) error {
query := render(
template.Must(template.New("").Parse(`
PRAGMA TablePathPrefix("{{ .TablePathPrefix }}");
@@ -317,19 +317,21 @@ func scanQuerySelect(ctx context.Context, c table.Client, prefix string) (err er
log.Printf("# Season, SeriesId: %d, SeasonId: %d, Title: %s, Air date: %s", seriesID, seasonID, title, date)
}
}
+
return res.Err()
},
)
}
-func fillTablesWithData(ctx context.Context, c table.Client, prefix string) (err error) {
+func fillTablesWithData(ctx context.Context, c table.Client, prefix string) error {
writeTx := table.TxControl(
table.BeginTx(
table.WithSerializableReadWrite(),
),
table.CommitTx(),
)
- err = c.Do(ctx,
+
+ return c.Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
_, _, err = s.Execute(ctx, writeTx, render(fill, templateConfig{
TablePathPrefix: prefix,
@@ -338,16 +340,16 @@ func fillTablesWithData(ctx context.Context, c table.Client, prefix string) (err
table.ValueParam("$seasonsData", getSeasonsData()),
table.ValueParam("$episodesData", getEpisodesData()),
))
+
return err
},
)
- return err
}
-func createTables(ctx context.Context, c table.Client, prefix string) (err error) {
- err = c.Do(ctx,
+func createTables(ctx context.Context, c table.Client, prefix string) error {
+ return c.Do(ctx,
func(ctx context.Context, s table.Session) error {
- return s.CreateTable(ctx, path.Join(prefix, "series"),
+ err := s.CreateTable(ctx, path.Join(prefix, "series"),
options.WithColumn("series_id", types.Optional(types.TypeUint64)),
options.WithColumn("title", types.Optional(types.TypeUTF8)),
options.WithColumn("series_info", types.Optional(types.TypeUTF8)),
@@ -355,15 +357,11 @@ func createTables(ctx context.Context, c table.Client, prefix string) (err error
options.WithColumn("comment", types.Optional(types.TypeUTF8)),
options.WithPrimaryKeyColumn("series_id"),
)
- },
- )
- if err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
- err = c.Do(ctx,
- func(ctx context.Context, s table.Session) error {
- return s.CreateTable(ctx, path.Join(prefix, "seasons"),
+ err = s.CreateTable(ctx, path.Join(prefix, "seasons"),
options.WithColumn("series_id", types.Optional(types.TypeUint64)),
options.WithColumn("season_id", types.Optional(types.TypeUint64)),
options.WithColumn("title", types.Optional(types.TypeUTF8)),
@@ -371,15 +369,11 @@ func createTables(ctx context.Context, c table.Client, prefix string) (err error
options.WithColumn("last_aired", types.Optional(types.TypeUint64)),
options.WithPrimaryKeyColumn("series_id", "season_id"),
)
- },
- )
- if err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
- err = c.Do(ctx,
- func(ctx context.Context, s table.Session) error {
- return s.CreateTable(ctx, path.Join(prefix, "episodes"),
+ err = s.CreateTable(ctx, path.Join(prefix, "episodes"),
options.WithColumn("series_id", types.Optional(types.TypeUint64)),
options.WithColumn("season_id", types.Optional(types.TypeUint64)),
options.WithColumn("episode_id", types.Optional(types.TypeUint64)),
@@ -387,17 +381,17 @@ func createTables(ctx context.Context, c table.Client, prefix string) (err error
options.WithColumn("air_date", types.Optional(types.TypeUint64)),
options.WithPrimaryKeyColumn("series_id", "season_id", "episode_id"),
)
+ if err != nil {
+ return err
+ }
+
+ return nil
},
)
- if err != nil {
- return err
- }
-
- return nil
}
-func describeTable(ctx context.Context, c table.Client, path string) (err error) {
- err = c.Do(ctx,
+func describeTable(ctx context.Context, c table.Client, path string) error {
+ return c.Do(ctx,
func(ctx context.Context, s table.Session) error {
desc, err := s.DescribeTable(ctx, path)
if err != nil {
@@ -407,10 +401,10 @@ func describeTable(ctx context.Context, c table.Client, path string) (err error)
for i := range desc.Columns {
log.Printf("column, name: %s, %s", desc.Columns[i].Type, desc.Columns[i].Name)
}
+
return nil
},
)
- return
}
func render(t *template.Template, data interface{}) string {
@@ -419,5 +413,6 @@ func render(t *template.Template, data interface{}) string {
if err != nil {
panic(err)
}
+
return buf.String()
}
diff --git a/examples/basic/xorm/data.go b/examples/basic/xorm/data.go
index eb085e19c..c6cfbb3fe 100644
--- a/examples/basic/xorm/data.go
+++ b/examples/basic/xorm/data.go
@@ -49,6 +49,7 @@ func getData() (series []*Series, seasons []*Seasons, episodes []*Episodes) {
seasons = append(seasons, seasonsData...)
episodes = append(episodes, episodesData...)
}
+
return
}
@@ -112,6 +113,7 @@ func getDataForITCrowd(seriesID string) (series *Series, seasons []*Seasons, epi
episodes = append(episodes, episodeData(seasonID, uuid.New().String(), title, date))
}
}
+
return series, seasons, episodes
}
@@ -201,6 +203,7 @@ func getDataForSiliconValley(seriesID string) (series *Series, seasons []*Season
episodes = append(episodes, episodeData(seasonID, uuid.New().String(), title, date))
}
}
+
return series, seasons, episodes
}
@@ -211,5 +214,6 @@ func date(date string) time.Time {
if err != nil {
panic(err)
}
+
return t
}
diff --git a/examples/basic/xorm/main.go b/examples/basic/xorm/main.go
index be8f8cbcc..8a0961af5 100644
--- a/examples/basic/xorm/main.go
+++ b/examples/basic/xorm/main.go
@@ -7,12 +7,11 @@ import (
"time"
_ "github.com/lib/pq"
+ _ "github.com/ydb-platform/ydb-go-sdk/v3"
_ "modernc.org/sqlite"
"xorm.io/builder"
"xorm.io/xorm"
xormLog "xorm.io/xorm/log"
-
- _ "github.com/ydb-platform/ydb-go-sdk/v3"
)
var envNotFoundMessage = `DSN environment variable not defined
@@ -77,6 +76,7 @@ func prepareScheme(db *xorm.Engine) error {
}
err = db.CreateTables(&Series{}, &Seasons{}, &Episodes{})
+
return err
}
@@ -89,6 +89,7 @@ func fillData(db *xorm.Engine) error {
if _, err := session.Insert(&series, &seasons, &episodes); err != nil {
return err
}
+
return nil
}
@@ -178,5 +179,6 @@ func findEpisodesByTitle(db *xorm.Engine, fragment string) error {
e.ID, e.AirDate.Format(dateISO8601), e.Title,
)
}
+
return nil
}
diff --git a/examples/ddl/ddl.go b/examples/ddl/ddl.go
index 6641c913f..9e0d4725a 100644
--- a/examples/ddl/ddl.go
+++ b/examples/ddl/ddl.go
@@ -71,11 +71,13 @@ func executeQuery(ctx context.Context, c table.Client, prefix, query string) (er
err = c.Do(ctx,
func(ctx context.Context, s table.Session) error {
err = s.ExecuteSchemeQuery(ctx, fmt.Sprintf(query, prefix))
+
return err
},
)
if err != nil {
return err
}
+
return nil
}
diff --git a/examples/ddl/main.go b/examples/ddl/main.go
index 75bd8576d..6e219b001 100644
--- a/examples/ddl/main.go
+++ b/examples/ddl/main.go
@@ -8,7 +8,6 @@ import (
"path"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
)
diff --git a/examples/decimal/decimal.go b/examples/decimal/decimal.go
index 9934ca15e..51400f575 100644
--- a/examples/decimal/decimal.go
+++ b/examples/decimal/decimal.go
@@ -34,5 +34,6 @@ func render(t *template.Template, data interface{}) string {
if err != nil {
panic(err)
}
+
return buf.String()
}
diff --git a/examples/decimal/main.go b/examples/decimal/main.go
index 1662dc983..8e77c2ce1 100644
--- a/examples/decimal/main.go
+++ b/examples/decimal/main.go
@@ -9,7 +9,6 @@ import (
"path"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
@@ -131,6 +130,7 @@ func main() {
fmt.Println(p.String())
}
}
+
return res.Err()
},
)
diff --git a/examples/describe/main.go b/examples/describe/main.go
index cc8f7106c..93fb00333 100644
--- a/examples/describe/main.go
+++ b/examples/describe/main.go
@@ -11,7 +11,6 @@ import (
"text/template"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
"github.com/ydb-platform/ydb-go-sdk/v3/scheme"
@@ -102,10 +101,12 @@ func list(ctx context.Context, db *ydb.Driver, t *template.Template, p string) {
var err error
err = retry.Retry(ctx, func(ctx context.Context) (err error) {
dir, err = db.Scheme().ListDirectory(ctx, p)
+
return err
}, retry.WithIdempotent(true))
if err != nil {
fmt.Printf("list directory '%s' failed: %v\n", p, err)
+
return
}
@@ -122,10 +123,12 @@ func list(ctx context.Context, db *ydb.Driver, t *template.Template, p string) {
var desc options.Description
err = db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
desc, err = s.DescribeTable(ctx, pt)
+
return err
}, table.WithIdempotent())
if err != nil {
fmt.Printf("describe '%s' failed: %v\n", pt, err)
+
continue
}
desc.Name = pt
diff --git a/examples/go.mod b/examples/go.mod
index 141a8779d..4b8c940bb 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -1,6 +1,6 @@
module examples
-go 1.20
+go 1.21
require (
github.com/google/uuid v1.3.0
@@ -9,8 +9,8 @@ require (
github.com/prometheus/client_golang v1.13.0
github.com/ydb-platform/gorm-driver v0.0.5
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.1.2
- github.com/ydb-platform/ydb-go-sdk-prometheus v0.11.10
- github.com/ydb-platform/ydb-go-sdk/v3 v3.47.3
+ github.com/ydb-platform/ydb-go-sdk-prometheus/v2 v2.0.1
+ github.com/ydb-platform/ydb-go-sdk/v3 v3.54.0
github.com/ydb-platform/ydb-go-yc v0.10.1
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54
gorm.io/driver/postgres v1.5.0
@@ -32,7 +32,8 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
- github.com/jackc/pgx/v5 v5.3.0 // indirect
+ github.com/jackc/pgx/v5 v5.5.4 // indirect
+ github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
@@ -49,11 +50,10 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20220815090733-4c139c0154e2 // indirect
- github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a // indirect
- github.com/ydb-platform/ydb-go-sdk-metrics v0.16.3 // indirect
+ github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf // indirect
github.com/ydb-platform/ydb-go-yc-metadata v0.5.4 // indirect
golang.org/x/crypto v0.17.0 // indirect
- golang.org/x/mod v0.9.0 // indirect
+ golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.15.0 // indirect
@@ -62,7 +62,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/grpc v1.57.1 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.36.3 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
diff --git a/examples/go.sum b/examples/go.sum
index 57cee1bb6..79278f3b3 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -770,7 +770,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -945,14 +944,17 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60=
-github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA=
github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
+github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
+github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -1098,7 +1100,6 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -1127,7 +1128,8 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rekby/fixenv v0.3.2/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
+github.com/rekby/fixenv v0.6.1 h1:jUFiSPpajT4WY2cYuc++7Y1zWrnCxnovGCIX72PZniM=
+github.com/rekby/fixenv v0.6.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -1195,14 +1197,12 @@ github.com/ydb-platform/gorm-driver v0.0.5 h1:q6Cg/iSFw4TAmSyMh25YM0GRmr6LVM2gnF
github.com/ydb-platform/gorm-driver v0.0.5/go.mod h1:fkCvWZlA3PzL5MiMc7yFOzxUOzLpY1uT8yZo+e4SV4Y=
github.com/ydb-platform/xorm v0.0.3 h1:MXk42lANB6r/MMLg/XdJfyXJycGUDlCeLiMlLGDKVPw=
github.com/ydb-platform/xorm v0.0.3/go.mod h1:hFsU7EUF0o3S+l5c0eyP2yPVjJ0d4gsFdqCsyazzwBc=
-github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a h1:9wx+kCrCQCdwmDe1AFW5yAHdzlo+RV7lcy6y7Zq661s=
-github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
+github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf h1:ckwNHVo4bv2tqNkgx3W3HANh3ta1j6TR5qw08J1A7Tw=
+github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.1.2 h1:EYSI1kulnHb0H0zt3yOw4cRj4ABMSMGwNe43D+fX7e4=
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.1.2/go.mod h1:Xfjce+VMU9yJVr1lj60yK2fFPWjB4jr/4cp3K7cjzi4=
-github.com/ydb-platform/ydb-go-sdk-metrics v0.16.3 h1:30D5jErLAiGjchVG2D9JiCLbST5LpAiyS7DoUtHkWsU=
-github.com/ydb-platform/ydb-go-sdk-metrics v0.16.3/go.mod h1:bqOjIBSt5LtA8fcTprRPGLvlQGkNlqBSRqnL+yZUJh4=
-github.com/ydb-platform/ydb-go-sdk-prometheus v0.11.10 h1:eXRJ8nKGv5Dyz7qTDFraahyqlSmOf1/8JqUtlxGlA4o=
-github.com/ydb-platform/ydb-go-sdk-prometheus v0.11.10/go.mod h1:7OffPa+OmsJgIP5G+2Cg5oP9+xB5UJSLm5AUpLxi5Uc=
+github.com/ydb-platform/ydb-go-sdk-prometheus/v2 v2.0.1 h1:Lsir3AC2VQOTlp8UjZY9zQdCVfWvBNHT3hZn+jSGoo0=
+github.com/ydb-platform/ydb-go-sdk-prometheus/v2 v2.0.1/go.mod h1:vofSH6XG0Cr04RV+V3fLp5apOhwDqj1kSoYD9/lmzmE=
github.com/ydb-platform/ydb-go-yc v0.8.3/go.mod h1:zUolAFGzJ5XG8uwiseTLr9Lapm7L7hdVdZgLSuv9FXE=
github.com/ydb-platform/ydb-go-yc v0.10.1 h1:9SBUpR94tzasEzqYSbBuuEp9mY/jV6xbwPMy3muvV7U=
github.com/ydb-platform/ydb-go-yc v0.10.1/go.mod h1:9HaZmOHUWy2MpJ4GZw9j9gR2I82/kb6H8fjsu8b2lxQ=
@@ -1239,6 +1239,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
+go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -1265,6 +1267,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
@@ -1323,10 +1326,12 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
+golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1387,6 +1392,7 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
@@ -1537,6 +1543,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1550,6 +1557,7 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
@@ -1650,6 +1658,7 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
@@ -1945,8 +1954,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/examples/pagination/cities.go b/examples/pagination/cities.go
index 2fd8aa846..620e9ee72 100644
--- a/examples/pagination/cities.go
+++ b/examples/pagination/cities.go
@@ -69,6 +69,7 @@ func selectPaging(
}()
if !res.NextResultSet(ctx) || !res.HasNextRow() {
empty = true
+
return res.Err()
}
var addr string
@@ -83,9 +84,11 @@ func selectPaging(
}
fmt.Printf("\t%v, School #%v, Address: %v\n", *lastCity, *lastNum, addr)
}
+
return res.Err()
},
)
+
return empty, err
}
@@ -112,8 +115,10 @@ func fillTableWithData(ctx context.Context, c table.Client, prefix string) (err
_, _, err = s.Execute(ctx, writeTx, query, table.NewQueryParameters(
table.ValueParam("$schoolsData", getSchoolData()),
))
+
return err
})
+
return err
}
diff --git a/examples/pagination/main.go b/examples/pagination/main.go
index 4510f1f3a..24690610b 100644
--- a/examples/pagination/main.go
+++ b/examples/pagination/main.go
@@ -8,7 +8,6 @@ import (
"path"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
)
diff --git a/examples/read_table/main.go b/examples/read_table/main.go
index 931672e6f..2e72d944a 100644
--- a/examples/read_table/main.go
+++ b/examples/read_table/main.go
@@ -9,7 +9,6 @@ import (
"path"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
diff --git a/examples/read_table/orders.go b/examples/read_table/orders.go
index 7255608ef..c9e007193 100644
--- a/examples/read_table/orders.go
+++ b/examples/read_table/orders.go
@@ -31,6 +31,7 @@ func dropTableIfExists(ctx context.Context, c table.Client, path string) (err er
if !ydb.IsOperationErrorSchemeError(err) {
return err
}
+
return nil
}
@@ -76,6 +77,7 @@ func render(t *template.Template, data interface{}) string {
if err != nil {
panic(err)
}
+
return buf.String()
}
@@ -116,6 +118,7 @@ func fillTable(ctx context.Context, c table.Client, prefix string) (err error) {
),
),
)
+
return err
},
)
@@ -126,6 +129,7 @@ func order(customerID, orderID uint64, description, date string) types.Value {
if err != nil {
panic(err)
}
+
return types.StructValue(
types.StructFieldValue("customer_id", types.Uint64Value(customerID)),
types.StructFieldValue("order_id", types.Uint64Value(orderID)),
@@ -173,8 +177,10 @@ func readTable(ctx context.Context, c table.Client, path string, opts ...options
}
}
}
+
return res.Err()
},
)
+
return err
}
diff --git a/examples/serverless/healthcheck/main.go b/examples/serverless/healthcheck/main.go
index fa44c3b72..5e828aa31 100644
--- a/examples/serverless/healthcheck/main.go
+++ b/examples/serverless/healthcheck/main.go
@@ -32,6 +32,7 @@ func (u *URLs) String() string {
// Set appends new value to URLs holder
func (u *URLs) Set(s string) error {
u.urls = append(u.urls, s)
+
return nil
}
diff --git a/examples/serverless/healthcheck/service.go b/examples/serverless/healthcheck/service.go
index c56953407..7e5ecb486 100644
--- a/examples/serverless/healthcheck/service.go
+++ b/examples/serverless/healthcheck/service.go
@@ -14,7 +14,6 @@ import (
"time"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
@@ -43,6 +42,7 @@ func getService(ctx context.Context, dsn string, opts ...ydb.Option) (s *service
s.db, err = ydb.Open(ctx, dsn, opts...)
if err != nil {
err = fmt.Errorf("connect error: %w", err)
+
return
}
err = s.createTableIfNotExists(ctx)
@@ -53,8 +53,10 @@ func getService(ctx context.Context, dsn string, opts ...ydb.Option) (s *service
})
if err != nil {
once = sync.Once{}
+
return nil, err
}
+
return s, nil
}
@@ -83,6 +85,7 @@ func (s *service) createTableIfNotExists(ctx context.Context) error {
AUTO_PARTITIONING_BY_LOAD = ENABLED
);`, path.Join(s.db.Name(), prefix),
)
+
return s.db.Table().Do(ctx,
func(ctx context.Context, s table.Session) error {
return s.ExecuteSchemeQuery(ctx, query)
@@ -109,6 +112,7 @@ func (s *service) ping(ctx context.Context, path string) (code int32, err error)
defer func() {
_ = response.Body.Close()
}()
+
return int32(response.StatusCode), nil
}
@@ -160,6 +164,7 @@ func (s *service) upsertRows(ctx context.Context, rows []row) (err error) {
if err != nil {
return err.Error()
}
+
return ""
}(rows[i].err))),
)
@@ -186,12 +191,14 @@ func (s *service) upsertRows(ctx context.Context, rows []row) (err error) {
table.ValueParam("$rows", types.ListValue(values...)),
),
)
+
return err
},
)
if err != nil {
return fmt.Errorf("error on upsert rows: %w", err)
}
+
return nil
}
@@ -209,5 +216,6 @@ func Serverless(ctx context.Context) error {
return fmt.Errorf("error on create service: %w", err)
}
defer s.Close(ctx)
+
return s.check(ctx, strings.Split(os.Getenv("URLS"), ","))
}
diff --git a/examples/serverless/url_shortener/main.go b/examples/serverless/url_shortener/main.go
index 40eadc06a..7e8ad0919 100644
--- a/examples/serverless/url_shortener/main.go
+++ b/examples/serverless/url_shortener/main.go
@@ -93,6 +93,7 @@ func main() {
if err != nil {
fmt.Println()
fmt.Println("Create service failed. Re-run with flag '-log-level=warn' and see logs")
+
return
}
defer s.Close(ctx)
diff --git a/examples/serverless/url_shortener/service.go b/examples/serverless/url_shortener/service.go
index 528549ce6..041c55d9d 100644
--- a/examples/serverless/url_shortener/service.go
+++ b/examples/serverless/url_shortener/service.go
@@ -21,8 +21,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
- ydbMetrics "github.com/ydb-platform/ydb-go-sdk-prometheus"
-
+ ydbMetrics "github.com/ydb-platform/ydb-go-sdk-prometheus/v2"
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
@@ -46,6 +45,7 @@ func hash(s string) (string, error) {
if err != nil {
return "", err
}
+
return hex.EncodeToString(hasher.Sum(nil)), nil
}
@@ -63,6 +63,7 @@ func render(t *template.Template, data interface{}) string {
if err != nil {
panic(err)
}
+
return buf.String()
}
@@ -149,6 +150,7 @@ func getService(ctx context.Context, dsn string, opts ...ydb.Option) (s *service
s.db, err = ydb.Open(ctx, dsn, opts...)
if err != nil {
err = fmt.Errorf("connect error: %w", err)
+
return
}
@@ -163,13 +165,16 @@ func getService(ctx context.Context, dsn string, opts ...ydb.Option) (s *service
if err != nil {
_ = s.db.Close(ctx)
err = fmt.Errorf("error on create table: %w", err)
+
return
}
})
if err != nil {
once = sync.Once{}
+
return nil, err
}
+
return s, nil
}
@@ -193,9 +198,11 @@ func (s *service) createTable(ctx context.Context) (err error) {
TablePathPrefix: path.Join(s.db.Name(), prefix),
},
)
+
return s.db.Table().Do(ctx,
func(ctx context.Context, s table.Session) error {
err := s.ExecuteSchemeQuery(ctx, query)
+
return err
},
)
@@ -237,9 +244,11 @@ func (s *service) insertShort(ctx context.Context, url string) (h string, err er
),
options.WithCollectStatsModeBasic(),
)
+
return
},
)
+
return h, err
}
@@ -276,6 +285,7 @@ func (s *service) selectLong(ctx context.Context, hash string) (url string, err
),
options.WithCollectStatsModeBasic(),
)
+
return err
},
)
@@ -291,9 +301,11 @@ func (s *service) selectLong(ctx context.Context, hash string) (url string, err
err = res.ScanNamed(
named.OptionalWithDefault("src", &src),
)
+
return src, err
}
}
+
return "", fmt.Errorf("hash '%s' is not found", hash)
}
@@ -306,6 +318,7 @@ func successToString(b bool) string {
if b {
return "true"
}
+
return "false"
}
@@ -333,6 +346,7 @@ func (s *service) handleIndex(w http.ResponseWriter, r *http.Request) {
tpl, err = template.ParseFS(static, "static/index.html")
if err != nil {
writeResponse(w, http.StatusInternalServerError, err.Error())
+
return
}
w.Header().Set("Content-Type", "text/html")
@@ -342,6 +356,7 @@ func (s *service) handleIndex(w http.ResponseWriter, r *http.Request) {
}
if err = tpl.Execute(w, data); err != nil {
writeResponse(w, http.StatusInternalServerError, err.Error())
+
return
}
}
@@ -371,16 +386,19 @@ func (s *service) handleShorten(w http.ResponseWriter, r *http.Request) {
url, err = io.ReadAll(r.Body)
if err != nil {
writeResponse(w, http.StatusInternalServerError, err.Error())
+
return
}
if !isLongCorrect(string(url)) {
err = fmt.Errorf("'%s' is not a valid URL", url)
writeResponse(w, http.StatusBadRequest, err.Error())
+
return
}
hash, err = s.insertShort(r.Context(), string(url))
if err != nil {
writeResponse(w, http.StatusInternalServerError, err.Error())
+
return
}
w.Header().Set("Content-Type", "application/text")
@@ -412,11 +430,13 @@ func (s *service) handleLonger(w http.ResponseWriter, r *http.Request) {
if !isShortCorrect(path[len(path)-1]) {
err = fmt.Errorf("'%s' is not a valid short path", path[len(path)-1])
writeResponse(w, http.StatusBadRequest, err.Error())
+
return
}
url, err = s.selectLong(r.Context(), path[len(path)-1])
if err != nil {
writeResponse(w, http.StatusInternalServerError, err.Error())
+
return
}
http.Redirect(w, r, url, http.StatusSeeOther)
@@ -433,6 +453,7 @@ func Serverless(w http.ResponseWriter, r *http.Request) {
)
if err != nil {
writeResponse(w, http.StatusInternalServerError, err.Error())
+
return
}
defer s.Close(r.Context())
diff --git a/examples/topic/cdc-cache-bus-freeseats/cache.go b/examples/topic/cdc-cache-bus-freeseats/cache.go
index ada1aac22..4e67084f6 100644
--- a/examples/topic/cdc-cache-bus-freeseats/cache.go
+++ b/examples/topic/cdc-cache-bus-freeseats/cache.go
@@ -35,6 +35,7 @@ func (c *Cache) Get(key string) (int64, bool) {
if time.Now().After(item.ExpiresAt) {
delete(c.values, key)
+
return 0, false
}
diff --git a/examples/topic/cdc-cache-bus-freeseats/database.go b/examples/topic/cdc-cache-bus-freeseats/database.go
index 218b892b6..43ad188ce 100644
--- a/examples/topic/cdc-cache-bus-freeseats/database.go
+++ b/examples/topic/cdc-cache-bus-freeseats/database.go
@@ -32,6 +32,7 @@ func createTables(ctx context.Context, db *ydb.Driver) error {
if ydb.IsOperationErrorSchemeError(err) {
err = nil
}
+
return err
})
if err != nil {
@@ -59,6 +60,7 @@ UPSERT INTO bus (id, freeSeats) VALUES ("bus1", 40), ("bus2", 60);
if err != nil {
return fmt.Errorf("failed insert rows: %w", err)
}
+
return nil
}
@@ -104,6 +106,7 @@ func connect() *ydb.Driver {
panic(fmt.Errorf("failed to create to ydb: %w", err))
}
log.Printf("connected to database")
+
return db
}
diff --git a/examples/topic/cdc-cache-bus-freeseats/webserver.go b/examples/topic/cdc-cache-bus-freeseats/webserver.go
index 790339b53..3825fabce 100644
--- a/examples/topic/cdc-cache-bus-freeseats/webserver.go
+++ b/examples/topic/cdc-cache-bus-freeseats/webserver.go
@@ -55,6 +55,7 @@ func (s *server) GetFreeSeatsHandler(writer http.ResponseWriter, request *http.R
freeSeats, err := s.getFreeSeats(ctx, id)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
+
return
}
duration := time.Since(start)
@@ -73,6 +74,7 @@ func (s *server) BuyTicketHandler(writer http.ResponseWriter, request *http.Requ
} else {
http.Error(writer, err.Error(), http.StatusInternalServerError)
}
+
return
}
//nolint:gocritic
@@ -81,7 +83,7 @@ func (s *server) BuyTicketHandler(writer http.ResponseWriter, request *http.Requ
s.writeAnswer(writer, freeSeats, duration)
}
-func (s *server) writeAnswer(writer http.ResponseWriter, freeSeats int64, duration time.Duration) {
+func (s *server) writeAnswer(writer io.Writer, freeSeats int64, duration time.Duration) {
_, _ = fmt.Fprintf(writer, "%v\n\nDuration: %v\n", freeSeats, duration)
}
@@ -105,6 +107,7 @@ func (s *server) getContentFromDB(ctx context.Context, id string) (int64, error)
err := s.db.Table().DoTx(ctx, func(ctx context.Context, tx table.TransactionActor) error {
var err error
freeSeats, err = s.getFreeSeatsTx(ctx, tx, id)
+
return err
})
@@ -129,6 +132,7 @@ SELECT freeSeats FROM bus WHERE id=$id;
if !res.NextRow() {
freeSeats = 0
+
return 0, errors.New("not found")
}
@@ -157,11 +161,13 @@ DECLARE $id AS Text;
UPDATE bus SET freeSeats = freeSeats - 1 WHERE id=$id;
`, table.NewQueryParameters(table.ValueParam("$id", types.UTF8Value(id))))
+
return err
})
if err == nil {
freeSeats--
}
+
return freeSeats, err
}
@@ -192,6 +198,7 @@ func (s *server) IndexPageHandler(writer http.ResponseWriter, request *http.Requ
})
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
+
return
}
diff --git a/examples/topic/cdc-fill-and-read/main.go b/examples/topic/cdc-fill-and-read/main.go
index b4ebf7c95..d0cfdbe47 100644
--- a/examples/topic/cdc-fill-and-read/main.go
+++ b/examples/topic/cdc-fill-and-read/main.go
@@ -10,7 +10,6 @@ import (
"time"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topictypes"
diff --git a/examples/topic/cdc-fill-and-read/tables.go b/examples/topic/cdc-fill-and-read/tables.go
index fcf5050f5..a522bdf11 100644
--- a/examples/topic/cdc-fill-and-read/tables.go
+++ b/examples/topic/cdc-fill-and-read/tables.go
@@ -29,6 +29,7 @@ func dropTableIfExists(ctx context.Context, c table.Client, path string) (err er
if !ydb.IsOperationErrorSchemeError(err) {
return err
}
+
return nil
}
@@ -60,11 +61,13 @@ WITH (
MODE = 'NEW_AND_OLD_IMAGES'
)
`, prefix, tableName)
+
return s.ExecuteSchemeQuery(ctx, query)
})
if err != nil {
return fmt.Errorf("failed to add changefeed to test table: %w", err)
}
+
return nil
}
@@ -90,6 +93,7 @@ VALUES
)
_ = c.DoTx(ctx, func(ctx context.Context, tx table.TransactionActor) error {
_, err := tx.Execute(ctx, query, params)
+
return err
})
@@ -114,6 +118,7 @@ WHERE id=$id
)
_ = c.DoTx(ctx, func(ctx context.Context, tx table.TransactionActor) error {
_, err := tx.Execute(ctx, query, params)
+
return err
})
diff --git a/examples/topic/topicreader/topicreader_advanced.go b/examples/topic/topicreader/topicreader_advanced.go
index cc1cb29be..962f4700b 100644
--- a/examples/topic/topicreader/topicreader_advanced.go
+++ b/examples/topic/topicreader/topicreader_advanced.go
@@ -36,6 +36,7 @@ func (m *MyMessage) UnmarshalYDBTopicMessage(data []byte) error {
m.ID = data[0]
m.ChangeType = data[1]
m.Delta = binary.BigEndian.Uint32(data[2:])
+
return nil
}
diff --git a/examples/topic/topicreader/topicreader_simple.go b/examples/topic/topicreader/topicreader_simple.go
index a652567c5..6fb568037 100644
--- a/examples/topic/topicreader/topicreader_simple.go
+++ b/examples/topic/topicreader/topicreader_simple.go
@@ -5,10 +5,9 @@ import (
"fmt"
"io"
- firestore "google.golang.org/genproto/firestore/bundle"
-
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicreader"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicsugar"
+ firestore "google.golang.org/genproto/firestore/bundle"
)
// PrintMessageContent is simple example for easy start read messages
diff --git a/examples/topic/topicreader/topicreader_trace.go b/examples/topic/topicreader/topicreader_trace.go
index 2de678993..28ab11427 100644
--- a/examples/topic/topicreader/topicreader_trace.go
+++ b/examples/topic/topicreader/topicreader_trace.go
@@ -44,6 +44,7 @@ func ExplicitPartitionStartStopHandler(ctx context.Context, db *ydb.Driver) {
if err != nil {
stopReader()
}
+
return nil
},
OnReaderPartitionReadStopResponse: func(
@@ -57,6 +58,7 @@ func ExplicitPartitionStartStopHandler(ctx context.Context, db *ydb.Driver) {
stopReader()
}
}
+
return nil
},
},
@@ -107,6 +109,7 @@ func PartitionStartStopHandlerAndOwnReadProgressStorage(ctx context.Context, db
if err != nil {
stopReader()
}
+
return nil
}
@@ -121,6 +124,7 @@ func PartitionStartStopHandlerAndOwnReadProgressStorage(ctx context.Context, db
stopReader()
}
}
+
return nil
}
diff --git a/examples/topic/topicwriter/topicwriter.go b/examples/topic/topicwriter/topicwriter.go
index 7faecd584..a378f8a90 100644
--- a/examples/topic/topicwriter/topicwriter.go
+++ b/examples/topic/topicwriter/topicwriter.go
@@ -12,16 +12,19 @@ import (
func ConnectSimple(ctx context.Context, db *ydb.Driver) *topicwriter.Writer {
writer, _ := db.Topic().StartWriter("topicName")
+
return writer
}
func ConnectWithSyncWrite(ctx context.Context, db *ydb.Driver) *topicwriter.Writer {
writer, _ := db.Topic().StartWriter("topicName", topicoptions.WithSyncWrite(true))
+
return writer
}
func ConnectSelectCodec(ctx context.Context, db *ydb.Driver) *topicwriter.Writer {
writer, _ := db.Topic().StartWriter("topicName", topicoptions.WithCodec(topictypes.CodecGzip))
+
return writer
}
diff --git a/examples/ttl/main.go b/examples/ttl/main.go
index ff7836037..b1a8ab963 100644
--- a/examples/ttl/main.go
+++ b/examples/ttl/main.go
@@ -8,7 +8,6 @@ import (
"path"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
)
diff --git a/examples/ttl/series.go b/examples/ttl/series.go
index 9aff311ea..a6e4753c3 100644
--- a/examples/ttl/series.go
+++ b/examples/ttl/series.go
@@ -62,6 +62,7 @@ func readExpiredBatchTransaction(ctx context.Context, c table.Client, prefix str
table.ValueParam("$prev_timestamp", types.Uint64Value(prevTimestamp)),
table.ValueParam("$prev_doc_id", types.Uint64Value(prevDocID)),
))
+
return err
},
)
@@ -71,6 +72,7 @@ func readExpiredBatchTransaction(ctx context.Context, c table.Client, prefix str
if res.Err() != nil {
return nil, res.Err()
}
+
return res, nil
}
@@ -97,9 +99,11 @@ func deleteDocumentWithTimestamp(ctx context.Context,
table.ValueParam("$doc_id", types.Uint64Value(lastDocID)),
table.ValueParam("$timestamp", types.Uint64Value(timestamp)),
))
+
return err
},
)
+
return err
}
@@ -137,12 +141,14 @@ func deleteExpired(ctx context.Context, c table.Client, prefix string, queue, ti
return err
}
}
+
return res.Err()
}()
if err != nil {
return err
}
}
+
return nil
}
@@ -196,9 +202,11 @@ func readDocument(ctx context.Context, c table.Client, prefix, url string) error
} else {
fmt.Println("\tNot found")
}
+
return res.Err()
},
)
+
return err
}
@@ -234,9 +242,11 @@ func addDocument(ctx context.Context, c table.Client, prefix, url, html string,
table.ValueParam("$html", types.TextValue(html)),
table.ValueParam("$timestamp", types.Uint64Value(timestamp)),
))
+
return err
},
)
+
return err
}
diff --git a/examples/ttl_readtable/main.go b/examples/ttl_readtable/main.go
index 54fd72d27..e867056d7 100644
--- a/examples/ttl_readtable/main.go
+++ b/examples/ttl_readtable/main.go
@@ -8,7 +8,6 @@ import (
"path"
environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
-
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
)
diff --git a/examples/ttl_readtable/series.go b/examples/ttl_readtable/series.go
index cb6fb62ec..0ed5c33a3 100644
--- a/examples/ttl_readtable/series.go
+++ b/examples/ttl_readtable/series.go
@@ -47,6 +47,7 @@ func deleteExpiredDocuments(ctx context.Context, c table.Client, prefix string,
for i := range ids {
k[i] = types.StructValue(types.StructFieldValue("doc_id", types.Uint64Value(ids[i])))
}
+
return k
}()...)
@@ -60,9 +61,11 @@ func deleteExpiredDocuments(ctx context.Context, c table.Client, prefix string,
table.ValueParam("$timestamp", types.Uint64Value(timestamp)),
),
)
+
return err
},
)
+
return err
}
@@ -78,6 +81,7 @@ func deleteExpiredRange(ctx context.Context, c table.Client, prefix string, time
options.ReadKeyRange(keyRange),
options.ReadColumn("doc_id"),
options.ReadColumn("ts"))
+
return err
},
)
@@ -136,6 +140,7 @@ func deleteExpired(ctx context.Context, c table.Client, prefix string, timestamp
err := c.Do(ctx,
func(ctx context.Context, s table.Session) (err error) {
res, err = s.DescribeTable(ctx, path.Join(prefix, "documents"), options.WithShardKeyBounds())
+
return err
},
)
@@ -177,6 +182,7 @@ func readDocument(ctx context.Context, c table.Client, prefix, url string) error
_, res, err = s.Execute(ctx, readTx, query, table.NewQueryParameters(
table.ValueParam("$url", types.TextValue(url))),
)
+
return err
},
)
@@ -239,9 +245,11 @@ func addDocument(ctx context.Context, c table.Client, prefix, url, html string,
table.ValueParam("$html", types.TextValue(html)),
table.ValueParam("$timestamp", types.Uint64Value(timestamp))),
)
+
return err
},
)
+
return err
}
diff --git a/go.mod b/go.mod
index db13a5944..339491ffc 100644
--- a/go.mod
+++ b/go.mod
@@ -1,23 +1,23 @@
module github.com/ydb-platform/ydb-go-sdk/v3
-go 1.20
+go 1.21
require (
github.com/golang-jwt/jwt/v4 v4.4.1
github.com/google/uuid v1.3.0
github.com/jonboulle/clockwork v0.3.0
- github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a
+ github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf
golang.org/x/sync v0.3.0
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
google.golang.org/grpc v1.57.1
- google.golang.org/protobuf v1.31.0
+ google.golang.org/protobuf v1.33.0
)
// requires for tests only
require (
- go.uber.org/mock v0.3.1-0.20231011042131-892b665398ec // indirect
- github.com/rekby/fixenv v0.3.2
+ github.com/rekby/fixenv v0.6.1
github.com/stretchr/testify v1.7.1
+ go.uber.org/mock v0.4.0
)
require (
diff --git a/go.sum b/go.sum
index f58f0f4f3..4cfd88ee1 100644
--- a/go.sum
+++ b/go.sum
@@ -24,8 +24,6 @@ github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kU
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
@@ -49,6 +47,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -58,38 +57,33 @@ github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUB
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rekby/fixenv v0.3.2 h1:6AOdQ9Boaa/lOQJTY8GDmQRIhg3S3SD0mIEPkuDSkoQ=
-github.com/rekby/fixenv v0.3.2/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
+github.com/rekby/fixenv v0.6.1 h1:jUFiSPpajT4WY2cYuc++7Y1zWrnCxnovGCIX72PZniM=
+github.com/rekby/fixenv v0.6.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a h1:9wx+kCrCQCdwmDe1AFW5yAHdzlo+RV7lcy6y7Zq661s=
-github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf h1:ckwNHVo4bv2tqNkgx3W3HANh3ta1j6TR5qw08J1A7Tw=
+github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.uber.org/mock v0.3.1-0.20231011042131-892b665398ec h1:aB0WVMCyiVcqL1yMRLM4htiFlMvgdOml97GYnw9su5Q=
-go.uber.org/mock v0.3.1-0.20231011042131-892b665398ec/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
+go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
+go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -98,7 +92,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -106,13 +99,9 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
@@ -122,10 +111,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -159,8 +144,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/allocator/allocator.go b/internal/allocator/allocator.go
index 2c8c7b176..378e8d244 100644
--- a/internal/allocator/allocator.go
+++ b/internal/allocator/allocator.go
@@ -4,6 +4,7 @@ import (
"sync"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table"
)
@@ -50,6 +51,15 @@ type (
tableQueryAllocator
tableQueryYqlTextAllocator
tableQueryIDAllocator
+ queryExecuteQueryRequestAllocator
+ queryExecuteQueryRequestQueryContentAllocator
+ queryExecuteQueryResponsePartAllocator
+ queryQueryContentAllocator
+ queryTransactionControlAllocator
+ queryTransactionControlBeginTxAllocator
+ queryTransactionControlTxIDAllocator
+ queryTransactionSettingsAllocator
+ queryTransactionSettingsSerializableReadWriteAllocator
}
)
@@ -99,6 +109,15 @@ func (a *Allocator) Free() {
a.tableQueryAllocator.free()
a.tableQueryYqlTextAllocator.free()
a.tableQueryIDAllocator.free()
+ a.queryExecuteQueryRequestAllocator.free()
+ a.queryExecuteQueryRequestQueryContentAllocator.free()
+ a.queryExecuteQueryResponsePartAllocator.free()
+ a.queryQueryContentAllocator.free()
+ a.queryTransactionControlAllocator.free()
+ a.queryTransactionControlBeginTxAllocator.free()
+ a.queryTransactionControlTxIDAllocator.free()
+ a.queryTransactionSettingsAllocator.free()
+ a.queryTransactionSettingsSerializableReadWriteAllocator.free()
allocatorPool.Put(a)
}
@@ -110,6 +129,7 @@ type boolAllocator struct {
func (a *boolAllocator) Bool() (v *Ydb.Value_BoolValue) {
v = boolPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -128,6 +148,7 @@ type bytesAllocator struct {
func (a *bytesAllocator) Bytes() (v *Ydb.Value_BytesValue) {
v = bytesPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -146,6 +167,7 @@ type decimalAllocator struct {
func (a *decimalAllocator) Decimal() (v *Ydb.DecimalType) {
v = decimalPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -164,6 +186,7 @@ type dictAllocator struct {
func (a *dictAllocator) Dict() (v *Ydb.DictType) {
v = dictPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -182,6 +205,7 @@ type doubleAllocator struct {
func (a *doubleAllocator) Double() (v *Ydb.Value_DoubleValue) {
v = doublePool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -200,6 +224,7 @@ type floatAllocator struct {
func (a *floatAllocator) Float() (v *Ydb.Value_FloatValue) {
v = floatPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -218,6 +243,7 @@ type int32Allocator struct {
func (a *int32Allocator) Int32() (v *Ydb.Value_Int32Value) {
v = int32Pool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -236,6 +262,7 @@ type int64Allocator struct {
func (a *int64Allocator) Int64() (v *Ydb.Value_Int64Value) {
v = int64Pool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -254,6 +281,7 @@ type listAllocator struct {
func (a *listAllocator) List() (v *Ydb.ListType) {
v = listPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -272,6 +300,7 @@ type low128Allocator struct {
func (a *low128Allocator) Low128() (v *Ydb.Value_Low_128) {
v = low128Pool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -290,6 +319,7 @@ type nestedAllocator struct {
func (a *nestedAllocator) Nested() (v *Ydb.Value_NestedValue) {
v = nestedPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -308,6 +338,7 @@ type nullFlagAllocator struct {
func (a *nullFlagAllocator) NullFlag() (v *Ydb.Value_NullFlagValue) {
v = nullFlagPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -326,6 +357,7 @@ type optionalAllocator struct {
func (a *optionalAllocator) Optional() (v *Ydb.OptionalType) {
v = optionalPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -344,6 +376,7 @@ type pairAllocator struct {
func (a *pairAllocator) Pair() (v *Ydb.ValuePair) {
v = pairPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -361,16 +394,17 @@ type structAllocator struct {
func (a *structAllocator) Struct() (v *Ydb.StructType) {
v = structPool.Get()
- if cap(v.Members) <= 0 {
+ if cap(v.GetMembers()) <= 0 {
v.Members = make([]*Ydb.StructMember, 0, 10)
}
a.allocations = append(a.allocations, v)
+
return v
}
func (a *structAllocator) free() {
for _, v := range a.allocations {
- members := v.Members
+ members := v.GetMembers()
for i := range members {
members[i] = nil
}
@@ -388,6 +422,7 @@ type structMemberAllocator struct {
func (a *structMemberAllocator) StructMember() (v *Ydb.StructMember) {
v = structMemberPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -406,6 +441,7 @@ type textAllocator struct {
func (a *textAllocator) Text() (v *Ydb.Value_TextValue) {
v = textPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -424,12 +460,13 @@ type tupleAllocator struct {
func (a *tupleAllocator) Tuple() (v *Ydb.TupleType) {
v = tuplePool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
func (a *tupleAllocator) free() {
for _, v := range a.allocations {
- elements := v.Elements
+ elements := v.GetElements()
for i := range elements {
elements[i] = nil
}
@@ -447,6 +484,7 @@ type typeDecimalAllocator struct {
func (a *typeDecimalAllocator) TypeDecimal() (v *Ydb.Type_DecimalType) {
v = typeDecimalPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -465,6 +503,7 @@ type typeDictAllocator struct {
func (a *typeDictAllocator) TypeDict() (v *Ydb.Type_DictType) {
v = typeDictPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -483,6 +522,7 @@ type typeEmptyListAllocator struct {
func (a *typeEmptyListAllocator) TypeEmptyList() (v *Ydb.Type_EmptyListType) {
v = typeEmptyListPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -501,6 +541,7 @@ type typeEmptyDictAllocator struct {
func (a *typeEmptyDictAllocator) TypeEmptyDict() (v *Ydb.Type_EmptyDictType) {
v = typeEmptyDictPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -519,6 +560,7 @@ type typeAllocator struct {
func (a *typeAllocator) Type() (v *Ydb.Type) {
v = typePool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -537,6 +579,7 @@ type typeListAllocator struct {
func (a *typeListAllocator) TypeList() (v *Ydb.Type_ListType) {
v = typeListPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -555,6 +598,7 @@ type typeOptionalAllocator struct {
func (a *typeOptionalAllocator) TypeOptional() (v *Ydb.Type_OptionalType) {
v = typeOptionalPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -573,6 +617,7 @@ type typeStructAllocator struct {
func (a *typeStructAllocator) TypeStruct() (v *Ydb.Type_StructType) {
v = typeStructPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -591,6 +636,7 @@ type typeTupleAllocator struct {
func (a *typeTupleAllocator) TypeTuple() (v *Ydb.Type_TupleType) {
v = typeTuplePool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -609,6 +655,7 @@ type typeVariantAllocator struct {
func (a *typeVariantAllocator) TypeVariant() (v *Ydb.Type_VariantType) {
v = typeVariantPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -627,6 +674,7 @@ type typedValueAllocator struct {
func (a *typedValueAllocator) TypedValue() (v *Ydb.TypedValue) {
v = typedValuePool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -645,6 +693,7 @@ type uint32Allocator struct {
func (a *uint32Allocator) Uint32() (v *Ydb.Value_Uint32Value) {
v = uint32Pool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -663,6 +712,7 @@ type uint64Allocator struct {
func (a *uint64Allocator) Uint64() (v *Ydb.Value_Uint64Value) {
v = uint64Pool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -681,13 +731,14 @@ type valueAllocator struct {
func (a *valueAllocator) Value() (v *Ydb.Value) {
v = valuePool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
func (a *valueAllocator) free() {
for _, v := range a.allocations {
- items := v.Items
- pairs := v.Pairs
+ items := v.GetItems()
+ pairs := v.GetPairs()
for i := range items {
items[i] = nil
}
@@ -709,6 +760,7 @@ type variantAllocator struct {
func (a *variantAllocator) Variant() (v *Ydb.VariantType) {
v = variantPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -726,6 +778,7 @@ type variantStructItemsAllocator struct {
func (a *variantStructItemsAllocator) VariantStructItems() (v *Ydb.VariantType_StructItems) {
v = variantStructItemsPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -743,6 +796,7 @@ type variantTupleItemsAllocator struct {
func (a *variantTupleItemsAllocator) VariantTupleItems() (v *Ydb.VariantType_TupleItems) {
v = variantTupleItemsPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -760,6 +814,7 @@ type tableExecuteQueryResultAllocator struct {
func (a *tableExecuteQueryResultAllocator) TableExecuteQueryResult() (v *Ydb_Table.ExecuteQueryResult) {
v = tableExecuteQueryResultPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -778,6 +833,7 @@ type tableExecuteQueryRequestAllocator struct {
func (a *tableExecuteQueryRequestAllocator) TableExecuteDataQueryRequest() (v *Ydb_Table.ExecuteDataQueryRequest) {
v = tableExecuteDataQueryRequestPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -796,6 +852,7 @@ type tableQueryCachePolicyAllocator struct {
func (a *tableQueryCachePolicyAllocator) TableQueryCachePolicy() (v *Ydb_Table.QueryCachePolicy) {
v = tableQueryCachePolicyPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -814,6 +871,7 @@ type tableQueryAllocator struct {
func (a *tableQueryAllocator) TableQuery() (v *Ydb_Table.Query) {
v = tableQueryPool.Get()
a.allocations = append(a.allocations, v)
+
return v
}
@@ -833,6 +891,7 @@ func (a *tableQueryYqlTextAllocator) TableQueryYqlText(s string) (v *Ydb_Table.Q
v = tableQueryYqlTextPool.Get()
v.YqlText = s
a.allocations = append(a.allocations, v)
+
return v
}
@@ -851,6 +910,7 @@ func (a *tableQueryIDAllocator) TableQueryID(id string) (v *Ydb_Table.Query_Id)
v = tableQueryIDPool.Get()
v.Id = id
a.allocations = append(a.allocations, v)
+
return v
}
@@ -861,6 +921,183 @@ func (a *tableQueryIDAllocator) free() {
a.allocations = a.allocations[:0]
}
+type queryExecuteQueryRequestAllocator struct {
+ allocations []*Ydb_Query.ExecuteQueryRequest
+}
+
+func (a *queryExecuteQueryRequestAllocator) QueryExecuteQueryRequest() (
+ v *Ydb_Query.ExecuteQueryRequest,
+) {
+ v = queryExecuteQueryRequestPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryExecuteQueryRequestAllocator) free() {
+ for _, v := range a.allocations {
+ v.Reset()
+ queryExecuteQueryRequestPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryExecuteQueryResponsePartAllocator struct {
+ allocations []*Ydb_Query.ExecuteQueryResponsePart
+}
+
+func (a *queryExecuteQueryResponsePartAllocator) QueryExecuteQueryResponsePart() (
+ v *Ydb_Query.ExecuteQueryResponsePart,
+) {
+ v = queryExecuteQueryResponsePartPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryExecuteQueryResponsePartAllocator) free() {
+ for _, v := range a.allocations {
+ v.Reset()
+ queryExecuteQueryResponsePartPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryExecuteQueryRequestQueryContentAllocator struct {
+ allocations []*Ydb_Query.ExecuteQueryRequest_QueryContent
+}
+
+func (a *queryExecuteQueryRequestQueryContentAllocator) QueryExecuteQueryRequestQueryContent() (
+ v *Ydb_Query.ExecuteQueryRequest_QueryContent,
+) {
+ v = queryExecuteQueryRequestQueryContentPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryExecuteQueryRequestQueryContentAllocator) free() {
+ for _, v := range a.allocations {
+ queryExecuteQueryRequestQueryContentPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryTransactionControlAllocator struct {
+ allocations []*Ydb_Query.TransactionControl
+}
+
+func (a *queryTransactionControlAllocator) QueryTransactionControl() (v *Ydb_Query.TransactionControl) {
+ v = queryTransactionControlPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryTransactionControlAllocator) free() {
+ for _, v := range a.allocations {
+ v.Reset()
+ queryTransactionControlPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryTransactionControlBeginTxAllocator struct {
+ allocations []*Ydb_Query.TransactionControl_BeginTx
+}
+
+func (a *queryTransactionControlBeginTxAllocator) QueryTransactionControlBeginTx() (
+ v *Ydb_Query.TransactionControl_BeginTx,
+) {
+ v = queryTransactionControlBeginTxPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryTransactionControlBeginTxAllocator) free() {
+ for _, v := range a.allocations {
+ queryTransactionControlBeginTxPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryTransactionControlTxIDAllocator struct {
+ allocations []*Ydb_Query.TransactionControl_TxId
+}
+
+func (a *queryTransactionControlTxIDAllocator) QueryTransactionControlTxID() (v *Ydb_Query.TransactionControl_TxId) {
+ v = queryTransactionControlTxIDPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryTransactionControlTxIDAllocator) free() {
+ for _, v := range a.allocations {
+ queryTransactionControlTxIDPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryTransactionSettingsAllocator struct {
+ allocations []*Ydb_Query.TransactionSettings
+}
+
+func (a *queryTransactionSettingsAllocator) QueryTransactionSettings() (v *Ydb_Query.TransactionSettings) {
+ v = queryTransactionSettingsPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryTransactionSettingsAllocator) free() {
+ for _, v := range a.allocations {
+ v.Reset()
+ queryTransactionSettingsPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryTransactionSettingsSerializableReadWriteAllocator struct {
+ allocations []*Ydb_Query.TransactionSettings_SerializableReadWrite
+}
+
+func (a *queryTransactionSettingsSerializableReadWriteAllocator) QueryTransactionSettingsSerializableReadWrite() (
+ v *Ydb_Query.TransactionSettings_SerializableReadWrite,
+) {
+ v = queryTransactionSettingsSerializableReadWritePool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryTransactionSettingsSerializableReadWriteAllocator) free() {
+ for _, v := range a.allocations {
+ queryTransactionSettingsSerializableReadWritePool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
+type queryQueryContentAllocator struct {
+ allocations []*Ydb_Query.QueryContent
+}
+
+func (a *queryQueryContentAllocator) QueryQueryContent() (v *Ydb_Query.QueryContent) {
+ v = queryQueryContentPool.Get()
+ a.allocations = append(a.allocations, v)
+
+ return v
+}
+
+func (a *queryQueryContentAllocator) free() {
+ for _, v := range a.allocations {
+ v.Reset()
+ queryQueryContentPool.Put(v)
+ }
+ a.allocations = a.allocations[:0]
+}
+
type Pool[T any] sync.Pool
func (p *Pool[T]) Get() *T {
@@ -869,6 +1106,7 @@ func (p *Pool[T]) Get() *T {
var zero T
v = &zero
}
+
return v.(*T)
}
@@ -877,46 +1115,55 @@ func (p *Pool[T]) Put(t *T) {
}
var (
- allocatorPool Pool[Allocator]
- valuePool Pool[Ydb.Value]
- typePool Pool[Ydb.Type]
- typeDecimalPool Pool[Ydb.Type_DecimalType]
- typeListPool Pool[Ydb.Type_ListType]
- typeEmptyListPool Pool[Ydb.Type_EmptyListType]
- typeEmptyDictPool Pool[Ydb.Type_EmptyDictType]
- typeTuplePool Pool[Ydb.Type_TupleType]
- typeStructPool Pool[Ydb.Type_StructType]
- typeDictPool Pool[Ydb.Type_DictType]
- typeVariantPool Pool[Ydb.Type_VariantType]
- decimalPool Pool[Ydb.DecimalType]
- listPool Pool[Ydb.ListType]
- tuplePool Pool[Ydb.TupleType]
- structPool Pool[Ydb.StructType]
- dictPool Pool[Ydb.DictType]
- variantPool Pool[Ydb.VariantType]
- variantTupleItemsPool Pool[Ydb.VariantType_TupleItems]
- variantStructItemsPool Pool[Ydb.VariantType_StructItems]
- structMemberPool Pool[Ydb.StructMember]
- typeOptionalPool Pool[Ydb.Type_OptionalType]
- optionalPool Pool[Ydb.OptionalType]
- typedValuePool Pool[Ydb.TypedValue]
- boolPool Pool[Ydb.Value_BoolValue]
- bytesPool Pool[Ydb.Value_BytesValue]
- textPool Pool[Ydb.Value_TextValue]
- int32Pool Pool[Ydb.Value_Int32Value]
- uint32Pool Pool[Ydb.Value_Uint32Value]
- low128Pool Pool[Ydb.Value_Low_128]
- int64Pool Pool[Ydb.Value_Int64Value]
- uint64Pool Pool[Ydb.Value_Uint64Value]
- floatPool Pool[Ydb.Value_FloatValue]
- doublePool Pool[Ydb.Value_DoubleValue]
- nestedPool Pool[Ydb.Value_NestedValue]
- nullFlagPool Pool[Ydb.Value_NullFlagValue]
- pairPool Pool[Ydb.ValuePair]
- tableExecuteQueryResultPool Pool[Ydb_Table.ExecuteQueryResult]
- tableExecuteDataQueryRequestPool Pool[Ydb_Table.ExecuteDataQueryRequest]
- tableQueryCachePolicyPool Pool[Ydb_Table.QueryCachePolicy]
- tableQueryPool Pool[Ydb_Table.Query]
- tableQueryYqlTextPool Pool[Ydb_Table.Query_YqlText]
- tableQueryIDPool Pool[Ydb_Table.Query_Id]
+ allocatorPool Pool[Allocator]
+ valuePool Pool[Ydb.Value]
+ typePool Pool[Ydb.Type]
+ typeDecimalPool Pool[Ydb.Type_DecimalType]
+ typeListPool Pool[Ydb.Type_ListType]
+ typeEmptyListPool Pool[Ydb.Type_EmptyListType]
+ typeEmptyDictPool Pool[Ydb.Type_EmptyDictType]
+ typeTuplePool Pool[Ydb.Type_TupleType]
+ typeStructPool Pool[Ydb.Type_StructType]
+ typeDictPool Pool[Ydb.Type_DictType]
+ typeVariantPool Pool[Ydb.Type_VariantType]
+ decimalPool Pool[Ydb.DecimalType]
+ listPool Pool[Ydb.ListType]
+ tuplePool Pool[Ydb.TupleType]
+ structPool Pool[Ydb.StructType]
+ dictPool Pool[Ydb.DictType]
+ variantPool Pool[Ydb.VariantType]
+ variantTupleItemsPool Pool[Ydb.VariantType_TupleItems]
+ variantStructItemsPool Pool[Ydb.VariantType_StructItems]
+ structMemberPool Pool[Ydb.StructMember]
+ typeOptionalPool Pool[Ydb.Type_OptionalType]
+ optionalPool Pool[Ydb.OptionalType]
+ typedValuePool Pool[Ydb.TypedValue]
+ boolPool Pool[Ydb.Value_BoolValue]
+ bytesPool Pool[Ydb.Value_BytesValue]
+ textPool Pool[Ydb.Value_TextValue]
+ int32Pool Pool[Ydb.Value_Int32Value]
+ uint32Pool Pool[Ydb.Value_Uint32Value]
+ low128Pool Pool[Ydb.Value_Low_128]
+ int64Pool Pool[Ydb.Value_Int64Value]
+ uint64Pool Pool[Ydb.Value_Uint64Value]
+ floatPool Pool[Ydb.Value_FloatValue]
+ doublePool Pool[Ydb.Value_DoubleValue]
+ nestedPool Pool[Ydb.Value_NestedValue]
+ nullFlagPool Pool[Ydb.Value_NullFlagValue]
+ pairPool Pool[Ydb.ValuePair]
+ tableExecuteQueryResultPool Pool[Ydb_Table.ExecuteQueryResult]
+ tableExecuteDataQueryRequestPool Pool[Ydb_Table.ExecuteDataQueryRequest]
+ tableQueryCachePolicyPool Pool[Ydb_Table.QueryCachePolicy]
+ tableQueryPool Pool[Ydb_Table.Query]
+ tableQueryYqlTextPool Pool[Ydb_Table.Query_YqlText]
+ tableQueryIDPool Pool[Ydb_Table.Query_Id]
+ queryExecuteQueryRequestPool Pool[Ydb_Query.ExecuteQueryRequest]
+ queryExecuteQueryRequestQueryContentPool Pool[Ydb_Query.ExecuteQueryRequest_QueryContent]
+ queryExecuteQueryResponsePartPool Pool[Ydb_Query.ExecuteQueryResponsePart]
+ queryQueryContentPool Pool[Ydb_Query.QueryContent]
+ queryTransactionControlPool Pool[Ydb_Query.TransactionControl]
+ queryTransactionControlBeginTxPool Pool[Ydb_Query.TransactionControl_BeginTx]
+ queryTransactionControlTxIDPool Pool[Ydb_Query.TransactionControl_TxId]
+ queryTransactionSettingsPool Pool[Ydb_Query.TransactionSettings]
+ queryTransactionSettingsSerializableReadWritePool Pool[Ydb_Query.TransactionSettings_SerializableReadWrite]
)
diff --git a/internal/background/worker.go b/internal/background/worker.go
index 3b989d66d..91c0d1686 100644
--- a/internal/background/worker.go
+++ b/internal/background/worker.go
@@ -19,19 +19,15 @@ var (
// A Worker must not be copied after first use
type Worker struct {
- ctx context.Context
- workers sync.WaitGroup
- onceInit sync.Once
-
+ ctx context.Context
+ workers sync.WaitGroup
+ closeReason error
tasksCompleted empty.Chan
-
- m xsync.Mutex
-
- tasks chan backgroundTask
-
- closed bool
- stop context.CancelFunc
- closeReason error
+ tasks chan backgroundTask
+ stop context.CancelFunc
+ onceInit sync.Once
+ m xsync.Mutex
+ closed bool
}
type CallbackFunc func(ctx context.Context)
@@ -77,6 +73,7 @@ func (b *Worker) Close(ctx context.Context, err error) error {
b.m.WithLock(func() {
if b.closed {
resErr = xerrors.WithStackTrace(ErrAlreadyClosed)
+
return
}
diff --git a/internal/background/worker_test.go b/internal/background/worker_test.go
index 6a3c13748..2a188fb00 100644
--- a/internal/background/worker_test.go
+++ b/internal/background/worker_test.go
@@ -4,13 +4,13 @@ import (
"context"
"runtime"
"sync"
+ "sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
)
@@ -75,7 +75,7 @@ func TestWorkerClose(t *testing.T) {
w := NewWorker(ctx)
started := make(empty.Chan)
- stopped := xatomic.Bool{}
+ stopped := atomic.Bool{}
w.Start("test", func(innerCtx context.Context) {
close(started)
<-innerCtx.Done()
@@ -101,12 +101,12 @@ func TestWorkerConcurrentStartAndClose(t *testing.T) {
parallel := runtime.GOMAXPROCS(0)
- var counter xatomic.Int64
+ var counter atomic.Int64
ctx := xtest.Context(t)
w := NewWorker(ctx)
- stopNewStarts := xatomic.Bool{}
+ stopNewStarts := atomic.Bool{}
var wgStarters sync.WaitGroup
for i := 0; i < parallel; i++ {
wgStarters.Add(1)
diff --git a/internal/backoff/backoff.go b/internal/backoff/backoff.go
index c0c1fcb64..c3a6902fe 100644
--- a/internal/backoff/backoff.go
+++ b/internal/backoff/backoff.go
@@ -86,11 +86,12 @@ func New(opts ...option) logBackoff {
b := logBackoff{
r: xrand.New(xrand.WithLock()),
}
- for _, o := range opts {
- if o != nil {
- o(&b)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&b)
}
}
+
return b
}
@@ -106,6 +107,7 @@ func (b logBackoff) Delay(i int) time.Duration {
if f == d {
return f
}
+
return f + time.Duration(b.r.Int64(int64(d-f)+1))
}
@@ -113,6 +115,7 @@ func min(a, b uint) uint {
if a < b {
return a
}
+
return b
}
@@ -120,5 +123,6 @@ func max(a, b uint) uint {
if a > b {
return a
}
+
return b
}
diff --git a/internal/backoff/backoff_test.go b/internal/backoff/backoff_test.go
index 24cb77f8c..45cd7fd1e 100644
--- a/internal/backoff/backoff_test.go
+++ b/internal/backoff/backoff_test.go
@@ -15,6 +15,7 @@ func TestDelays(t *testing.T) {
if err != nil {
panic(err)
}
+
return d
}
b := New(
@@ -141,6 +142,7 @@ func TestLogBackoff(t *testing.T) {
act, eq,
)
}
+
continue
}
if gte := exp.gte; act <= gte {
@@ -172,6 +174,7 @@ func TestFastSlowDelaysWithoutJitter(t *testing.T) {
backoff: func() (backoff logBackoff) {
backoff = Fast
backoff.jitterLimit = 1
+
return backoff
}(),
exp: []time.Duration{
@@ -193,6 +196,7 @@ func TestFastSlowDelaysWithoutJitter(t *testing.T) {
backoff: func() (backoff logBackoff) {
backoff = Slow
backoff.jitterLimit = 1
+
return backoff
}(),
exp: []time.Duration{
diff --git a/internal/balancer/balancer.go b/internal/balancer/balancer.go
index 5f089688f..f69ec11e2 100644
--- a/internal/balancer/balancer.go
+++ b/internal/balancer/balancer.go
@@ -55,6 +55,7 @@ func (b *Balancer) HasNode(id uint32) bool {
if _, has := b.connectionsState.connByNodeID[id]; has {
return true
}
+
return false
}
@@ -80,8 +81,10 @@ func (b *Balancer) clusterDiscovery(ctx context.Context) (err error) {
if ctx.Err() == nil && xerrors.IsTimeoutError(err) {
return xerrors.WithStackTrace(xerrors.Retryable(err))
}
+
return xerrors.WithStackTrace(err)
}
+
return nil
},
retry.WithIdempotent(true),
@@ -94,7 +97,8 @@ func (b *Balancer) clusterDiscoveryAttempt(ctx context.Context) (err error) {
address = "ydb:///" + b.driverConfig.Endpoint()
onDone = trace.DriverOnBalancerClusterDiscoveryAttempt(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID(
+ "github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).clusterDiscoveryAttempt"),
address,
)
endpoints []endpoint.Endpoint
@@ -162,6 +166,7 @@ func endpointsDiff(newestEndpoints []endpoint.Endpoint, previousConns []conn.Con
dropped = append(dropped, c.Endpoint().Copy())
}
}
+
return nodes, added, dropped
}
@@ -169,14 +174,15 @@ func (b *Balancer) applyDiscoveredEndpoints(ctx context.Context, endpoints []end
var (
onDone = trace.DriverOnBalancerUpdate(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID(
+ "github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).applyDiscoveredEndpoints"),
b.config.DetectLocalDC,
)
previousConns []conn.Conn
)
defer func() {
nodes, added, dropped := endpointsDiff(endpoints, previousConns)
- onDone(nodes, added, dropped, localDC, nil)
+ onDone(nodes, added, dropped, localDC)
}()
connections := endpointsToConnections(b.pool, endpoints)
@@ -207,7 +213,7 @@ func (b *Balancer) applyDiscoveredEndpoints(ctx context.Context, endpoints []end
func (b *Balancer) Close(ctx context.Context) (err error) {
onDone := trace.DriverOnBalancerClose(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).Close"),
)
defer func() {
onDone(err)
@@ -233,7 +239,7 @@ func New(
var (
onDone = trace.DriverOnBalancerInit(
driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.New"),
driverConfig.Balancer().String(),
)
discoveryConfig = discoveryConfig.New(append(opts,
@@ -253,12 +259,9 @@ func New(
pool: pool,
localDCDetector: detectLocalDC,
}
- d, err := internalDiscovery.New(ctx, pool.Get(
+ d := internalDiscovery.New(ctx, pool.Get(
endpoint.New(driverConfig.Endpoint()),
), discoveryConfig)
- if err != nil {
- return nil, err
- }
b.discoveryClient = d
@@ -279,7 +282,7 @@ func New(
}
// run background discovering
if d := discoveryConfig.Interval(); d > 0 {
- b.discoveryRepeater = repeater.New(xcontext.WithoutDeadline(ctx),
+ b.discoveryRepeater = repeater.New(xcontext.ValueOnly(ctx),
d, b.clusterDiscoveryAttempt,
repeater.WithName("discovery"),
repeater.WithTrace(b.driverConfig.Trace()),
@@ -311,11 +314,13 @@ func (b *Balancer) NewStream(
var client grpc.ClientStream
err = b.wrapCall(ctx, func(ctx context.Context, cc conn.Conn) error {
client, err = cc.NewStream(ctx, desc, method, opts...)
+
return err
})
if err == nil {
return client, nil
}
+
return nil, err
}
@@ -348,8 +353,10 @@ func (b *Balancer) wrapCall(ctx context.Context, f func(ctx context.Context, cc
credentials.WithCredentials(b.driverConfig.Credentials()),
)
}
+
return xerrors.WithStackTrace(err)
}
+
return err
}
@@ -366,7 +373,7 @@ func (b *Balancer) connections() *connectionsState {
func (b *Balancer) getConn(ctx context.Context) (c conn.Conn, err error) {
onDone := trace.DriverOnBalancerChooseEndpoint(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).getConn"),
)
defer func() {
if err == nil {
@@ -397,6 +404,7 @@ func (b *Balancer) getConn(ctx context.Context) (c conn.Conn, err error) {
fmt.Errorf("%w: cannot get connection from Balancer after %d attempts", ErrNoEndpoints, failedCount),
)
}
+
return c, nil
}
@@ -405,5 +413,6 @@ func endpointsToConnections(p *conn.Pool, endpoints []endpoint.Endpoint) []conn.
for _, e := range endpoints {
conns = append(conns, p.Get(e))
}
+
return conns
}
diff --git a/internal/balancer/connections_state.go b/internal/balancer/connections_state.go
index 98afeba68..e9196ead7 100644
--- a/internal/balancer/connections_state.go
+++ b/internal/balancer/connections_state.go
@@ -35,6 +35,7 @@ func newConnectionsState(
} else {
res.all = res.prefer
}
+
return res
}
@@ -54,6 +55,7 @@ func (s *connectionsState) GetConnection(ctx context.Context) (_ conn.Conn, fail
try := func(conns []conn.Conn) conn.Conn {
c, tryFailed := s.selectRandomConnection(conns, false)
failedCount += tryFailed
+
return c
}
@@ -121,6 +123,7 @@ func connsToNodeIDMap(conns []conn.Conn) (nodes map[uint32]conn.Conn) {
for _, c := range conns {
nodes[c.Endpoint().NodeID()] = c
}
+
return nodes
}
@@ -146,6 +149,7 @@ func sortPreferConnections(
fallback = append(fallback, c)
}
}
+
return prefer, fallback
}
diff --git a/internal/balancer/ctx.go b/internal/balancer/ctx.go
index 434e64ede..9b4aeb209 100644
--- a/internal/balancer/ctx.go
+++ b/internal/balancer/ctx.go
@@ -18,5 +18,6 @@ func ContextEndpoint(ctx context.Context) (e Endpoint, ok bool) {
if e, ok = ctx.Value(ctxEndpointKey{}).(Endpoint); ok {
return e, true
}
+
return nil, false
}
diff --git a/internal/balancer/local_dc.go b/internal/balancer/local_dc.go
index d375ac680..e764af7d8 100644
--- a/internal/balancer/local_dc.go
+++ b/internal/balancer/local_dc.go
@@ -75,16 +75,19 @@ func detectFastestEndpoint(ctx context.Context, endpoints []endpoint.Endpoint) (
host, port, err := extractHostPort(ep.Address())
if err != nil {
lastErr = xerrors.WithStackTrace(err)
+
continue
}
addresses, err := net.DefaultResolver.LookupHost(ctx, host)
if err != nil {
lastErr = err
+
continue
}
if len(addresses) == 0 {
lastErr = xerrors.WithStackTrace(fmt.Errorf("no ips for fqdn: %q", host))
+
continue
}
@@ -105,6 +108,7 @@ func detectFastestEndpoint(ctx context.Context, endpoints []endpoint.Endpoint) (
if fastestAddress == "" {
return nil, xerrors.WithStackTrace(errors.New("failed to check fastest address"))
}
+
return addressToEndpoint[fastestAddress], nil
}
@@ -127,6 +131,7 @@ func detectLocalDC(ctx context.Context, endpoints []endpoint.Endpoint) (string,
if err == nil {
return fastest.Location(), nil
}
+
return "", err
}
@@ -143,6 +148,7 @@ func extractHostPort(address string) (host, port string, _ error) {
if err != nil {
return "", "", xerrors.WithStackTrace(err)
}
+
return host, port, nil
}
@@ -174,5 +180,6 @@ func splitEndpointsByLocation(endpoints []endpoint.Endpoint) map[string][]endpoi
location := ep.Location()
res[location] = append(res[location], ep)
}
+
return res
}
diff --git a/internal/bind/bind.go b/internal/bind/bind.go
index a19699a88..c6d1111c6 100644
--- a/internal/bind/bind.go
+++ b/internal/bind/bind.go
@@ -3,9 +3,9 @@ package bind
import (
"sort"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
- "github.com/ydb-platform/ydb-go-sdk/v3/table"
)
type blockID int
@@ -27,38 +27,40 @@ type Bind interface {
type Bindings []Bind
func (bindings Bindings) RewriteQuery(query string, args ...interface{}) (
- yql string, _ *table.QueryParameters, err error,
+ yql string, parameters []*params.Parameter, err error,
) {
if len(bindings) == 0 {
- var params []table.ParameterOption
- params, err = Params(args...)
+ parameters, err = Params(args...)
if err != nil {
return "", nil, xerrors.WithStackTrace(err)
}
- return query, table.NewQueryParameters(params...), nil
+
+ return query, parameters, nil
}
buffer := xstring.Buffer()
defer buffer.Free()
for i := range bindings {
- query, args, err = bindings[len(bindings)-1-i].RewriteQuery(query, args...)
- if err != nil {
- return "", nil, xerrors.WithStackTrace(err)
+ var e error
+ query, args, e = bindings[len(bindings)-1-i].RewriteQuery(query, args...)
+ if e != nil {
+ return "", nil, xerrors.WithStackTrace(e)
}
}
- params, err := Params(args...)
+ parameters, err = Params(args...)
if err != nil {
return "", nil, xerrors.WithStackTrace(err)
}
- return query, table.NewQueryParameters(params...), nil
+ return query, parameters, nil
}
func Sort(bindings []Bind) []Bind {
sort.Slice(bindings, func(i, j int) bool {
return bindings[i].blockID() < bindings[j].blockID()
})
+
return bindings
}
diff --git a/internal/bind/numeric_args.go b/internal/bind/numeric_args.go
index ecfc22787..89c9c4ecc 100644
--- a/internal/bind/numeric_args.go
+++ b/internal/bind/numeric_args.go
@@ -76,6 +76,7 @@ func (m NumericArgs) RewriteQuery(sql string, args ...interface{}) (
if len(newArgs) > 0 {
const prefix = "-- origin query with numeric args replacement\n"
+
return prefix + buffer.String(), newArgs, nil
}
@@ -101,18 +102,21 @@ func numericArgsStateFn(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos-width])
}
l.start = l.pos
+
return numericArgState
}
case '-':
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
if nextRune == '-' {
l.pos += width
+
return oneLineCommentState
}
case '/':
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
if nextRune == '*' {
l.pos += width
+
return multilineCommentState
}
case utf8.RuneError:
@@ -120,6 +124,7 @@ func numericArgsStateFn(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
@@ -149,9 +154,11 @@ func numericArgState(l *sqlLexer) stateFn {
numbers += string(r)
case isLetter(r):
numbers = ""
+
return l.rawStateFn
default:
l.pos -= width
+
return l.rawStateFn
}
}
diff --git a/internal/bind/params.go b/internal/bind/params.go
index 00df0504d..d0e6a82da 100644
--- a/internal/bind/params.go
+++ b/internal/bind/params.go
@@ -9,9 +9,9 @@ import (
"sort"
"time"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
- "github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
@@ -46,6 +46,7 @@ func toValue(v interface{}) (_ types.Value, err error) {
return types.NullValue(types.TypeInt32), nil
}
xx := int32(*x)
+
return types.NullableInt32Value(&xx), nil
case uint:
return types.Uint32Value(uint32(x)), nil
@@ -54,6 +55,7 @@ func toValue(v interface{}) (_ types.Value, err error) {
return types.NullValue(types.TypeUint32), nil
}
xx := uint32(*x)
+
return types.NullableUint32Value(&xx), nil
case int8:
return types.Int8Value(x), nil
@@ -108,6 +110,7 @@ func toValue(v interface{}) (_ types.Value, err error) {
for i := range x {
items[i] = types.TextValue(x[i])
}
+
return types.ListValue(items...), nil
case [16]byte:
return types.UUIDValue(x), nil
@@ -135,10 +138,11 @@ func supportNewTypeLink(x interface{}) string {
v.Add("labels", "enhancement,database/sql")
v.Add("template", "02_FEATURE_REQUEST.md")
v.Add("title", fmt.Sprintf("feat: Support new type `%T` in `database/sql` query args", x))
+
return "https://github.com/ydb-platform/ydb-go-sdk/issues/new?" + v.Encode()
}
-func toYdbParam(name string, value interface{}) (table.ParameterOption, error) {
+func toYdbParam(name string, value interface{}) (*params.Parameter, error) {
if na, ok := value.(driver.NamedValue); ok {
n, v := na.Name, na.Value
if n != "" {
@@ -153,7 +157,7 @@ func toYdbParam(name string, value interface{}) (table.ParameterOption, error) {
}
value = v
}
- if v, ok := value.(table.ParameterOption); ok {
+ if v, ok := value.(*params.Parameter); ok {
return v, nil
}
v, err := toValue(value)
@@ -166,39 +170,38 @@ func toYdbParam(name string, value interface{}) (table.ParameterOption, error) {
if name[0] != '$' {
name = "$" + name
}
- return table.ValueParam(name, v), nil
+
+ return params.Named(name, v), nil
}
-func Params(args ...interface{}) (params []table.ParameterOption, _ error) {
- params = make([]table.ParameterOption, 0, len(args))
+func Params(args ...interface{}) (parameters []*params.Parameter, _ error) {
+ parameters = make([]*params.Parameter, 0, len(args))
for i, arg := range args {
switch x := arg.(type) {
case driver.NamedValue:
if x.Name == "" {
switch xx := x.Value.(type) {
- case *table.QueryParameters:
+ case *params.Parameters:
if len(args) > 1 {
return nil, xerrors.WithStackTrace(errMultipleQueryParameters)
}
- xx.Each(func(name string, v types.Value) {
- params = append(params, table.ValueParam(name, v))
- })
- case table.ParameterOption:
- params = append(params, xx)
+ parameters = *xx
+ case *params.Parameter:
+ parameters = append(parameters, xx)
default:
x.Name = fmt.Sprintf("$p%d", i)
param, err := toYdbParam(x.Name, x.Value)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- params = append(params, param)
+ parameters = append(parameters, param)
}
} else {
param, err := toYdbParam(x.Name, x.Value)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- params = append(params, param)
+ parameters = append(parameters, param)
}
case sql.NamedArg:
if x.Name == "" {
@@ -208,26 +211,25 @@ func Params(args ...interface{}) (params []table.ParameterOption, _ error) {
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- params = append(params, param)
- case *table.QueryParameters:
+ parameters = append(parameters, param)
+ case *params.Parameters:
if len(args) > 1 {
return nil, xerrors.WithStackTrace(errMultipleQueryParameters)
}
- x.Each(func(name string, v types.Value) {
- params = append(params, table.ValueParam(name, v))
- })
- case table.ParameterOption:
- params = append(params, x)
+ parameters = *x
+ case *params.Parameter:
+ parameters = append(parameters, x)
default:
param, err := toYdbParam(fmt.Sprintf("$p%d", i), x)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- params = append(params, param)
+ parameters = append(parameters, param)
}
}
- sort.Slice(params, func(i, j int) bool {
- return params[i].Name() < params[j].Name()
+ sort.Slice(parameters, func(i, j int) bool {
+ return parameters[i].Name() < parameters[j].Name()
})
- return params, nil
+
+ return parameters, nil
}
diff --git a/internal/bind/params_test.go b/internal/bind/params_test.go
index 80d47b4a3..d715c07a1 100644
--- a/internal/bind/params_test.go
+++ b/internal/bind/params_test.go
@@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
@@ -346,27 +347,27 @@ func named(name string, value interface{}) driver.NamedValue {
func TestYdbParam(t *testing.T) {
for _, tt := range []struct {
src interface{}
- dst table.ParameterOption
+ dst *params.Parameter
err error
}{
{
- src: table.ValueParam("$a", types.Int32Value(42)),
- dst: table.ValueParam("$a", types.Int32Value(42)),
+ src: params.Named("$a", types.Int32Value(42)),
+ dst: params.Named("$a", types.Int32Value(42)),
err: nil,
},
{
src: named("a", int(42)),
- dst: table.ValueParam("$a", types.Int32Value(42)),
+ dst: params.Named("$a", types.Int32Value(42)),
err: nil,
},
{
src: named("$a", int(42)),
- dst: table.ValueParam("$a", types.Int32Value(42)),
+ dst: params.Named("$a", types.Int32Value(42)),
err: nil,
},
{
src: named("a", uint(42)),
- dst: table.ValueParam("$a", types.Uint32Value(42)),
+ dst: params.Named("$a", types.Uint32Value(42)),
err: nil,
},
{
@@ -389,50 +390,50 @@ func TestYdbParam(t *testing.T) {
func TestArgsToParams(t *testing.T) {
for _, tt := range []struct {
args []interface{}
- params []table.ParameterOption
+ params []*params.Parameter
err error
}{
{
args: []interface{}{},
- params: []table.ParameterOption{},
+ params: []*params.Parameter{},
err: nil,
},
{
args: []interface{}{
1, uint64(2), "3",
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
{
args: []interface{}{
table.NewQueryParameters(
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
),
table.NewQueryParameters(
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
),
},
err: errMultipleQueryParameters,
},
{
args: []interface{}{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
@@ -442,10 +443,10 @@ func TestArgsToParams(t *testing.T) {
sql.Named("$p1", types.Uint64Value(2)),
sql.Named("$p2", types.TextValue("3")),
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
@@ -455,23 +456,23 @@ func TestArgsToParams(t *testing.T) {
driver.NamedValue{Name: "$p1", Value: types.Uint64Value(2)},
driver.NamedValue{Name: "$p2", Value: types.TextValue("3")},
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
{
args: []interface{}{
- driver.NamedValue{Value: table.ValueParam("$p0", types.Int32Value(1))},
- driver.NamedValue{Value: table.ValueParam("$p1", types.Uint64Value(2))},
- driver.NamedValue{Value: table.ValueParam("$p2", types.TextValue("3"))},
+ driver.NamedValue{Value: params.Named("$p0", types.Int32Value(1))},
+ driver.NamedValue{Value: params.Named("$p1", types.Uint64Value(2))},
+ driver.NamedValue{Value: params.Named("$p2", types.TextValue("3"))},
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
@@ -481,37 +482,37 @@ func TestArgsToParams(t *testing.T) {
driver.NamedValue{Value: uint64(2)},
driver.NamedValue{Value: "3"},
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
{
args: []interface{}{
driver.NamedValue{Value: table.NewQueryParameters(
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
)},
},
- params: []table.ParameterOption{
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params: []*params.Parameter{
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
},
err: nil,
},
{
args: []interface{}{
driver.NamedValue{Value: table.NewQueryParameters(
- table.ValueParam("$p0", types.Int32Value(1)),
- table.ValueParam("$p1", types.Uint64Value(2)),
- table.ValueParam("$p2", types.TextValue("3")),
+ params.Named("$p0", types.Int32Value(1)),
+ params.Named("$p1", types.Uint64Value(2)),
+ params.Named("$p2", types.TextValue("3")),
)},
- driver.NamedValue{Value: table.ValueParam("$p1", types.Uint64Value(2))},
- driver.NamedValue{Value: table.ValueParam("$p2", types.TextValue("3"))},
+ driver.NamedValue{Value: params.Named("$p1", types.Uint64Value(2))},
+ driver.NamedValue{Value: params.Named("$p2", types.TextValue("3"))},
},
err: errMultipleQueryParameters,
},
diff --git a/internal/bind/positional_args.go b/internal/bind/positional_args.go
index 506a3d62e..e3c0afa13 100644
--- a/internal/bind/positional_args.go
+++ b/internal/bind/positional_args.go
@@ -65,6 +65,7 @@ func (m PositionalArgs) RewriteQuery(sql string, args ...interface{}) (
if position > 0 {
const prefix = "-- origin query with positional args replacement\n"
+
return prefix + buffer.String(), newArgs, nil
}
@@ -90,12 +91,14 @@ func positionalArgsStateFn(l *sqlLexer) stateFn {
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
if nextRune == '-' {
l.pos += width
+
return oneLineCommentState
}
case '/':
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
if nextRune == '*' {
l.pos += width
+
return multilineCommentState
}
case utf8.RuneError:
@@ -103,6 +106,7 @@ func positionalArgsStateFn(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
diff --git a/internal/bind/sql_lexer.go b/internal/bind/sql_lexer.go
index 23626b495..49fe30911 100644
--- a/internal/bind/sql_lexer.go
+++ b/internal/bind/sql_lexer.go
@@ -44,6 +44,7 @@ func backtickState(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
@@ -66,6 +67,7 @@ func singleQuoteState(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
@@ -88,6 +90,7 @@ func doubleQuoteState(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
@@ -109,6 +112,7 @@ func oneLineCommentState(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
@@ -143,6 +147,7 @@ func multilineCommentState(l *sqlLexer) stateFn {
l.parts = append(l.parts, l.src[l.start:l.pos])
l.start = l.pos
}
+
return nil
}
}
diff --git a/internal/certificates/certificates.go b/internal/certificates/certificates.go
index 6a7b1f12f..8282dce79 100644
--- a/internal/certificates/certificates.go
+++ b/internal/certificates/certificates.go
@@ -47,6 +47,7 @@ func loadFromFileCache(key string) (_ []*x509.Certificate, exists bool) {
if !ok {
panic(fmt.Sprintf("unexpected value type '%T'", value))
}
+
return certs, true
}
@@ -65,6 +66,7 @@ func FromFile(file string, opts ...FromFileOption) ([]*x509.Certificate, error)
if options.onHit != nil {
options.onHit()
}
+
return certs, nil
}
}
@@ -100,6 +102,7 @@ func loadFromPemCache(key string) (_ *x509.Certificate, exists bool) {
if !ok {
panic(fmt.Sprintf("unexpected value type '%T'", value))
}
+
return cert, true
}
@@ -120,6 +123,7 @@ func parseCertificate(der []byte, opts ...FromPemOption) (*x509.Certificate, err
if options.onHit != nil {
options.onHit()
}
+
return cert, nil
}
}
diff --git a/internal/cmd/gstack/main.go b/internal/cmd/gstack/main.go
new file mode 100644
index 000000000..12f427668
--- /dev/null
+++ b/internal/cmd/gstack/main.go
@@ -0,0 +1,222 @@
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/fs"
+ "os"
+ "path/filepath"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/cmd/gstack/utils"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gstack [path]\n")
+ flag.PrintDefaults()
+}
+
+func getCallExpressionsFromExpr(expr ast.Expr) (listOfCalls []*ast.CallExpr) {
+ switch expr := expr.(type) {
+ case *ast.SelectorExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ case *ast.IndexExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ case *ast.StarExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ case *ast.BinaryExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.Y)...)
+ case *ast.CallExpr:
+ listOfCalls = append(listOfCalls, expr)
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.Fun)...)
+ for _, arg := range expr.Args {
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(arg)...)
+ }
+ case *ast.CompositeLit:
+ for _, elt := range expr.Elts {
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(elt)...)
+ }
+ case *ast.UnaryExpr:
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.X)...)
+ case *ast.KeyValueExpr:
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.Value)...)
+ case *ast.FuncLit:
+ listOfCalls = append(listOfCalls, getListOfCallExpressionsFromBlockStmt(expr.Body)...)
+ }
+
+ return listOfCalls
+}
+
+func getExprFromDeclStmt(statement *ast.DeclStmt) (listOfExpressions []ast.Expr) {
+ decl, ok := statement.Decl.(*ast.GenDecl)
+ if !ok {
+ return listOfExpressions
+ }
+ for _, spec := range decl.Specs {
+ if spec, ok := spec.(*ast.ValueSpec); ok {
+ listOfExpressions = append(listOfExpressions, spec.Values...)
+ }
+ }
+
+ return listOfExpressions
+}
+
+func getCallExpressionsFromStmt(statement ast.Stmt) (listOfCallExpressions []*ast.CallExpr) {
+ var body *ast.BlockStmt
+ var listOfExpressions []ast.Expr
+ switch stmt := statement.(type) {
+ case *ast.IfStmt:
+ body = stmt.Body
+ case *ast.SwitchStmt:
+ body = stmt.Body
+ case *ast.TypeSwitchStmt:
+ body = stmt.Body
+ case *ast.SelectStmt:
+ body = stmt.Body
+ case *ast.ForStmt:
+ body = stmt.Body
+ case *ast.RangeStmt:
+ body = stmt.Body
+ case *ast.DeclStmt:
+ listOfExpressions = append(listOfExpressions, getExprFromDeclStmt(stmt)...)
+ for _, expr := range listOfExpressions {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(expr)...)
+ }
+ case *ast.CommClause:
+ stmts := stmt.Body
+ for _, stmt := range stmts {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromStmt(stmt)...)
+ }
+ case *ast.ExprStmt:
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(stmt.X)...)
+ case *ast.AssignStmt:
+ for _, rh := range stmt.Rhs {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(rh)...)
+ }
+ case *ast.ReturnStmt:
+ for _, result := range stmt.Results {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(result)...)
+ }
+ }
+ if body != nil {
+ listOfCallExpressions = append(
+ listOfCallExpressions,
+ getListOfCallExpressionsFromBlockStmt(body)...,
+ )
+ }
+
+ return listOfCallExpressions
+}
+
+func getListOfCallExpressionsFromBlockStmt(block *ast.BlockStmt) (listOfCallExpressions []*ast.CallExpr) {
+ for _, statement := range block.List {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromStmt(statement)...)
+ }
+
+ return listOfCallExpressions
+}
+
+func format(src []byte, path string, fset *token.FileSet, file *ast.File) ([]byte, error) {
+ var listOfArgs []utils.FunctionIDArg
+ for _, f := range file.Decls {
+ var listOfCalls []*ast.CallExpr
+ fn, ok := f.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ listOfCalls = getListOfCallExpressionsFromBlockStmt(fn.Body)
+ for _, call := range listOfCalls {
+ if function, ok := call.Fun.(*ast.SelectorExpr); ok && function.Sel.Name == "FunctionID" {
+ pack, ok := function.X.(*ast.Ident)
+ if !ok {
+ continue
+ }
+ if pack.Name == "stack" && len(call.Args) == 1 {
+ listOfArgs = append(listOfArgs, utils.FunctionIDArg{
+ FuncDecl: fn,
+ ArgPos: call.Args[0].Pos(),
+ ArgEnd: call.Args[0].End(),
+ })
+ }
+ }
+ }
+ }
+ if len(listOfArgs) != 0 {
+ fixed, err := utils.FixSource(fset, path, src, listOfArgs)
+ if err != nil {
+ return nil, err
+ }
+
+ return fixed, nil
+ }
+
+ return src, nil
+}
+
+func processFile(src []byte, path string, fset *token.FileSet, file *ast.File, info os.FileInfo) error {
+ formatted, err := format(src, path, fset, file)
+ if err != nil {
+ return err
+ }
+ if !bytes.Equal(src, formatted) {
+ err = utils.WriteFile(path, formatted, info.Mode().Perm())
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ args := flag.Args()
+
+ if len(args) != 1 {
+ flag.Usage()
+
+ return
+ }
+ _, err := os.Stat(args[0])
+ if err != nil {
+ panic(err)
+ }
+
+ fileSystem := os.DirFS(args[0])
+
+ err = fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error {
+ fset := token.NewFileSet()
+ if err != nil {
+ return err
+ }
+ if d.IsDir() {
+ return nil
+ }
+ if filepath.Ext(path) == ".go" {
+ info, err := os.Stat(path)
+ if err != nil {
+ return err
+ }
+ src, err := utils.ReadFile(path, info)
+ if err != nil {
+ return err
+ }
+ file, err := parser.ParseFile(fset, path, nil, 0)
+ if err != nil {
+ return err
+ }
+
+ return processFile(src, path, fset, file, info)
+ }
+
+ return nil
+ })
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/internal/cmd/gstack/utils/utils.go b/internal/cmd/gstack/utils/utils.go
new file mode 100644
index 000000000..19b35512d
--- /dev/null
+++ b/internal/cmd/gstack/utils/utils.go
@@ -0,0 +1,135 @@
+package utils
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/fs"
+ "os"
+ "path/filepath"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
+)
+
+type FunctionIDArg struct {
+ FuncDecl *ast.FuncDecl
+ ArgPos token.Pos
+ ArgEnd token.Pos
+}
+
+func ReadFile(filename string, info fs.FileInfo) ([]byte, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ size := int(info.Size())
+ src := make([]byte, size)
+ n, err := io.ReadFull(f, src)
+ if err != nil {
+ return nil, err
+ }
+ if n < size {
+ return nil, fmt.Errorf("error: size of %q changed during reading (from %d to %d bytes)", filename, size, n)
+ } else if n > size {
+ return nil, fmt.Errorf("error: size of %q changed during reading (from %d to >=%d bytes)", filename, size, len(src))
+ }
+
+ return src, nil
+}
+
+func FixSource(fset *token.FileSet, path string, src []byte, listOfArgs []FunctionIDArg) ([]byte, error) {
+ var fixed []byte
+ var previousArgEnd int
+ for _, arg := range listOfArgs {
+ argPosOffset := fset.Position(arg.ArgPos).Offset
+ argEndOffset := fset.Position(arg.ArgEnd).Offset
+ argument, err := makeCall(fset, path, arg)
+ if err != nil {
+ return nil, err
+ }
+ fixed = append(fixed, src[previousArgEnd:argPosOffset]...)
+ fixed = append(fixed, fmt.Sprintf("%q", argument)...)
+ previousArgEnd = argEndOffset
+ }
+ fixed = append(fixed, src[previousArgEnd:]...)
+
+ return fixed, nil
+}
+
+func WriteFile(filename string, formatted []byte, perm fs.FileMode) error {
+ fout, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+
+ defer fout.Close()
+
+ _, err = fout.Write(formatted)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func makeCall(fset *token.FileSet, path string, arg FunctionIDArg) (string, error) {
+ basePath := filepath.Join("github.com", "ydb-platform", version.Prefix, version.Major, "")
+ packageName, err := getPackageName(fset, arg)
+ if err != nil {
+ return "", err
+ }
+ filePath := filepath.Dir(filepath.Dir(path))
+ funcName, err := getFuncName(arg.FuncDecl)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(basePath, filePath, packageName) + "." + funcName, nil
+}
+
+func getFuncName(funcDecl *ast.FuncDecl) (string, error) {
+ if funcDecl.Recv != nil {
+ recvType := funcDecl.Recv.List[0].Type
+ prefix, err := getIdentNameFromExpr(recvType)
+ if err != nil {
+ return "", err
+ }
+
+ return prefix + "." + funcDecl.Name.Name, nil
+ }
+
+ return funcDecl.Name.Name, nil
+}
+
+func getIdentNameFromExpr(expr ast.Expr) (string, error) {
+ switch expr := expr.(type) {
+ case *ast.Ident:
+ return expr.Name, nil
+ case *ast.StarExpr:
+ prefix, err := getIdentNameFromExpr(expr.X)
+ if err != nil {
+ return "", err
+ }
+
+ return "(*" + prefix + ")", nil
+ case *ast.IndexExpr:
+ return getIdentNameFromExpr(expr.X)
+ case *ast.IndexListExpr:
+ return getIdentNameFromExpr(expr.X)
+ default:
+ return "", fmt.Errorf("error during getting ident from expr")
+ }
+}
+
+func getPackageName(fset *token.FileSet, arg FunctionIDArg) (string, error) {
+ file := fset.File(arg.ArgPos)
+ parsedFile, err := parser.ParseFile(fset, file.Name(), nil, parser.PackageClauseOnly)
+ if err != nil {
+ return "", fmt.Errorf("error during get package name function")
+ }
+
+ return parsedFile.Name.Name, nil
+}
diff --git a/internal/cmd/gtrace/.gitignore b/internal/cmd/gtrace/.gitignore
new file mode 100644
index 000000000..5239aed1b
--- /dev/null
+++ b/internal/cmd/gtrace/.gitignore
@@ -0,0 +1,2 @@
+gtrace
+gtrace.exe
diff --git a/internal/cmd/gtrace/gtrace b/internal/cmd/gtrace/gtrace
deleted file mode 100755
index 634cde9a3..000000000
Binary files a/internal/cmd/gtrace/gtrace and /dev/null differ
diff --git a/internal/cmd/gtrace/main.go b/internal/cmd/gtrace/main.go
index 95a72f0c2..99f2bf98a 100644
--- a/internal/cmd/gtrace/main.go
+++ b/internal/cmd/gtrace/main.go
@@ -16,15 +16,10 @@ import (
"os"
"path/filepath"
"strings"
- _ "unsafe" // For go:linkname.
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
-//go:linkname build_goodOSArchFile go/build.(*Context).goodOSArchFile
-//nolint:revive
-func build_goodOSArchFile(*build.Context, string, map[string]bool) bool
-
//nolint:gocyclo
func main() {
var (
@@ -64,8 +59,6 @@ func main() {
var writers []*Writer
if isGoGenerate {
- // We should respect Go suffixes like `_linux.go`.
- name, tags, ext := splitOSArchTags(&buildCtx, gofile)
openFile := func(name string) (*os.File, func()) {
var f *os.File
//nolint:gofumpt
@@ -79,9 +72,12 @@ func main() {
if err != nil {
log.Fatal(err)
}
+
return f, func() { f.Close() }
}
- f, clean := openFile(name + "_gtrace" + tags + ext)
+ ext := filepath.Ext(gofile)
+ name := strings.TrimSuffix(gofile, ext)
+ f, clean := openFile(name + "_gtrace" + ext)
defer clean()
writers = append(writers, &Writer{
Context: buildCtx,
@@ -102,7 +98,7 @@ func main() {
)
fset := token.NewFileSet()
for _, name := range buildPkg.GoFiles {
- base, _, _ := splitOSArchTags(&buildCtx, name)
+ base := strings.TrimSuffix(name, filepath.Ext(name))
if isGenerated(base, "_gtrace") {
continue
}
@@ -159,6 +155,7 @@ func main() {
if n == nil {
item = nil
depth--
+
return true
}
defer func() {
@@ -175,6 +172,7 @@ func main() {
if item != nil {
item.Ident = v
}
+
return false
case *ast.CommentGroup:
@@ -185,6 +183,7 @@ func main() {
}
}
}
+
return false
case *ast.StructType:
@@ -193,6 +192,7 @@ func main() {
items = append(items, item)
item = nil
}
+
return false
}
@@ -228,6 +228,7 @@ func main() {
"skipping hook %s due to error: %v",
name, err,
)
+
continue
}
t.Hooks = append(t.Hooks, Hook{
@@ -289,12 +290,14 @@ func buildFunc(info *types.Info, traces map[string]*Trace, fn *ast.FuncType) (re
return nil, xerrors.WithStackTrace(err)
}
ret.Result = append(ret.Result, result)
+
return ret, nil
case *ast.Ident:
if t, ok := traces[x.Name]; ok {
t.Nested = true
ret.Result = append(ret.Result, t)
+
return ret, nil
}
}
@@ -305,37 +308,6 @@ func buildFunc(info *types.Info, traces map[string]*Trace, fn *ast.FuncType) (re
)
}
-func splitOSArchTags(ctx *build.Context, name string) (base, tags, ext string) {
- fileTags := make(map[string]bool)
- build_goodOSArchFile(ctx, name, fileTags)
- ext = filepath.Ext(name)
- switch len(fileTags) {
- case 0: // *
- base = strings.TrimSuffix(name, ext)
-
- case 1: // *_GOOS or *_GOARCH
- i := strings.LastIndexByte(name, '_')
-
- base = name[:i]
- tags = strings.TrimSuffix(name[i:], ext)
-
- case 2: // *_GOOS_GOARCH
- var i int
- i = strings.LastIndexByte(name, '_')
- i = strings.LastIndexByte(name[:i], '_')
-
- base = name[:i]
- tags = strings.TrimSuffix(name[i:], ext)
-
- default:
- panic(fmt.Sprintf(
- "gtrace: internal error: unexpected number of OS/arch tags: %d",
- len(fileTags),
- ))
- }
- return
-}
-
type Package struct {
*types.Package
@@ -396,6 +368,7 @@ func rsplit(s string, c byte) (s1, s2 string) {
if i == -1 {
return s, ""
}
+
return s[:i], s[i+1:]
}
@@ -411,6 +384,7 @@ func scanBuildConstraints(r io.Reader) (cs []string, err error) {
comm = bytes.TrimSpace(comm)
if bytes.HasPrefix(comm, []byte("+build")) {
cs = append(cs, string(line))
+
continue
}
}
@@ -418,6 +392,7 @@ func scanBuildConstraints(r io.Reader) (cs []string, err error) {
break
}
}
+
return cs, nil
}
@@ -428,5 +403,6 @@ func isGenerated(base, suffix string) bool {
}
n := len(base)
m := i + len(suffix)
+
return m == n || base[m] == '_'
}
diff --git a/internal/cmd/gtrace/writer.go b/internal/cmd/gtrace/writer.go
index 00e099ba6..fcc87a43e 100644
--- a/internal/cmd/gtrace/writer.go
+++ b/internal/cmd/gtrace/writer.go
@@ -160,6 +160,7 @@ func (w *Writer) typeImports(dst []dep, t types.Type) []dep {
typName: obj.Name(),
})
}
+
return dst
}
@@ -175,6 +176,7 @@ func unwrapStruct(t types.Type) (n *types.Named, s *types.Struct) {
if ok {
s, _ = n.Underlying().(*types.Struct)
}
+
return
}
@@ -194,6 +196,7 @@ func (w *Writer) funcImports(dst []dep, fn *Func) []dep {
dst = w.funcImports(dst, fn)
}
}
+
return dst
}
@@ -201,6 +204,7 @@ func (w *Writer) traceImports(dst []dep, t *Trace) []dep {
for _, h := range t.Hooks {
dst = w.funcImports(dst, h.Func)
}
+
return dst
}
@@ -212,6 +216,7 @@ func (w *Writer) importDeps(deps []dep) {
n := len(deps)
deps[i], deps[n-1] = deps[n-1], deps[i]
deps = deps[:n-1]
+
continue
}
seen[d.pkgPath] = true
@@ -230,6 +235,7 @@ func (w *Writer) importDeps(deps []dep) {
if std0 != std1 {
return std0
}
+
return d0.pkgPath < d1.pkgPath
})
w.line(`import (`)
@@ -250,6 +256,7 @@ func (w *Writer) importDeps(deps []dep) {
func (w *Writer) isStdLib(pkg string) bool {
w.ensureStdLibMapping()
s := strings.Split(pkg, "/")[0]
+
return w.std[s]
}
@@ -520,6 +527,7 @@ func (w *Writer) hookFuncCall(fn *Func, name string, args []string) {
})
w.line(`}`)
})
+
return
}
}
@@ -532,6 +540,7 @@ func nameParam(p *Param) (s string) {
if s == "" {
s = firstChar(ident(typeBasename(p.Type)))
}
+
return unexported(s)
}
@@ -540,6 +549,7 @@ func (w *Writer) declareParams(src []Param) (names []string) {
for i := range src {
names[i] = w.declare(nameParam(&src[i]))
}
+
return names
}
@@ -548,10 +558,12 @@ func flattenParams(params []Param) (dst []Param) {
_, s := unwrapStruct(params[i].Type)
if s != nil {
dst = flattenStruct(dst, s)
+
continue
}
dst = append(dst, params[i])
}
+
return dst
}
@@ -560,6 +572,7 @@ func typeBasename(t types.Type) (name string) {
if name == "" {
name = lo
}
+
return name
}
@@ -582,6 +595,7 @@ func flattenStruct(dst []Param, s *types.Struct) []Param {
Type: typ,
})
})
+
return dst
}
@@ -592,16 +606,18 @@ func (w *Writer) constructParams(params []Param, names []string) (res []string)
var v string
v, names = w.constructStruct(n, s, names)
res = append(res, v)
+
continue
}
name := names[0]
names = names[1:]
res = append(res, name)
}
+
return res
}
-func (w *Writer) constructStruct(n *types.Named, s *types.Struct, vars []string) (string, []string) {
+func (w *Writer) constructStruct(n types.Type, s *types.Struct, vars []string) (string, []string) {
p := w.declare("p")
// maybe skip pointers from flattening to not allocate anyhing during trace.
w.line(`var `, p, ` `, w.typeString(n))
@@ -614,6 +630,7 @@ func (w *Writer) constructStruct(n *types.Named, s *types.Struct, vars []string)
vars = vars[1:]
w.line(p, `.`, v.Name(), ` = `, name)
}
+
return p, vars
}
@@ -726,6 +743,7 @@ func (w *Writer) hookFuncShortcut(fn *Func, name string) {
func (w *Writer) zeroReturn(fn *Func) {
if !fn.HasResult() {
w.line(`return`)
+
return
}
w.code(`return `)
@@ -753,6 +771,7 @@ func (w *Writer) funcParams(params []Param) (vars []string) {
vars = append(vars, w.funcParam(¶ms[i]))
}
w.code(`)`)
+
return
}
@@ -760,6 +779,7 @@ func (w *Writer) funcParam(p *Param) (name string) {
name = w.declare(nameParam(p))
w.code(name, ` `)
w.code(w.typeString(p.Type))
+
return name
}
@@ -875,6 +895,7 @@ func haveNames(params []Param) bool {
return true
}
}
+
return false
}
@@ -883,6 +904,7 @@ func (w *Writer) typeString(t types.Type) string {
if pkg.Path() == w.pkg.Path() {
return "" // same package; unqualified
}
+
return pkg.Name()
})
}
@@ -922,6 +944,7 @@ func exported(s string) string {
if r == utf8.RuneError {
panic("invalid string")
}
+
return string(unicode.ToUpper(r)) + s[size:]
}
@@ -930,6 +953,7 @@ func unexported(s string) string {
if r == utf8.RuneError {
panic("invalid string")
}
+
return string(unicode.ToLower(r)) + s[size:]
}
@@ -938,6 +962,7 @@ func firstChar(s string) string {
if r == utf8.RuneError {
panic("invalid string")
}
+
return string(r)
}
@@ -984,6 +1009,7 @@ func tempName(names ...string) string {
}
sb.WriteString(name)
}
+
return sb.String()
}
@@ -1006,10 +1032,12 @@ func (s *scope) set(v string) bool {
s.vars[v] = decl{
where: fmt.Sprintf("%s:%d", file, line),
}
+
return true
}
func (s *scope) where(v string) string {
d := s.vars[v]
+
return d.where
}
diff --git a/internal/conn/config.go b/internal/conn/config.go
index 305fc8c71..df82f3a85 100644
--- a/internal/conn/config.go
+++ b/internal/conn/config.go
@@ -10,7 +10,7 @@ import (
type Config interface {
DialTimeout() time.Duration
- Trace() *trace.Driver
ConnectionTTL() time.Duration
+ Trace() *trace.Driver
GrpcDialOptions() []grpc.DialOption
}
diff --git a/internal/conn/conn.go b/internal/conn/conn.go
index c9a1d755a..b9bb75105 100644
--- a/internal/conn/conn.go
+++ b/internal/conn/conn.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"sync"
+ "sync/atomic"
"time"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
@@ -16,7 +17,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/meta"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/response"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
@@ -54,8 +54,8 @@ type conn struct {
done chan struct{}
endpoint endpoint.Endpoint // ro access
closed bool
- state xatomic.Uint32
- lastUsage time.Time
+ state atomic.Uint32
+ lastUsage *lastUsage
onClose []func(*conn)
onTransportErrors []func(ctx context.Context, cc Conn, cause error)
}
@@ -72,13 +72,15 @@ func (c *conn) Ping(ctx context.Context) error {
if !isAvailable(cc) {
return c.wrapError(errUnavailableConnection)
}
+
return nil
}
func (c *conn) LastUsage() time.Time {
c.mtx.RLock()
defer c.mtx.RUnlock()
- return c.lastUsage
+
+ return c.lastUsage.Get()
}
func (c *conn) IsState(states ...State) bool {
@@ -92,10 +94,18 @@ func (c *conn) IsState(states ...State) bool {
return false
}
+func (c *conn) NodeID() uint32 {
+ if c != nil {
+ return c.endpoint.NodeID()
+ }
+
+ return 0
+}
+
func (c *conn) park(ctx context.Context) (err error) {
onDone := trace.DriverOnConnPark(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).park"),
c.Endpoint(),
)
defer func() {
@@ -122,17 +132,11 @@ func (c *conn) park(ctx context.Context) (err error) {
return nil
}
-func (c *conn) NodeID() uint32 {
- if c != nil {
- return c.endpoint.NodeID()
- }
- return 0
-}
-
func (c *conn) Endpoint() endpoint.Endpoint {
if c != nil {
return c.endpoint
}
+
return nil
}
@@ -144,10 +148,11 @@ func (c *conn) setState(ctx context.Context, s State) State {
if state := State(c.state.Swap(uint32(s))); state != s {
trace.DriverOnConnStateChange(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).setState"),
c.endpoint.Copy(), state,
)(s)
}
+
return s
}
@@ -163,6 +168,7 @@ func (c *conn) Unban(ctx context.Context) State {
}
c.setState(ctx, newState)
+
return newState
}
@@ -190,7 +196,7 @@ func (c *conn) realConn(ctx context.Context) (cc *grpc.ClientConn, err error) {
onDone := trace.DriverOnConnDial(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).realConn"),
c.endpoint.Copy(),
)
defer func() {
@@ -207,6 +213,10 @@ func (c *conn) realConn(ctx context.Context) (cc *grpc.ClientConn, err error) {
}, c.config.GrpcDialOptions()...,
)...)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
defer func() {
c.onTransportError(ctx, err)
}()
@@ -234,12 +244,6 @@ func (c *conn) onTransportError(ctx context.Context, cause error) {
}
}
-func (c *conn) touchLastUsage() {
- c.mtx.Lock()
- defer c.mtx.Unlock()
- c.lastUsage = time.Now()
-}
-
func isAvailable(raw *grpc.ClientConn) bool {
return raw != nil && raw.GetState() == connectivity.Ready
}
@@ -252,12 +256,14 @@ func (c *conn) close(ctx context.Context) (err error) {
err = c.cc.Close()
c.cc = nil
c.setState(ctx, Offline)
+
return c.wrapError(err)
}
func (c *conn) isClosed() bool {
c.mtx.RLock()
defer c.mtx.RUnlock()
+
return c.closed
}
@@ -271,7 +277,7 @@ func (c *conn) Close(ctx context.Context) (err error) {
onDone := trace.DriverOnConnClose(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).Close"),
c.Endpoint(),
)
defer func() {
@@ -304,7 +310,7 @@ func (c *conn) Invoke(
useWrapping = UseWrapping(ctx)
onDone = trace.DriverOnConnInvoke(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).Invoke"),
c.endpoint, trace.Method(method),
)
cc *grpc.ClientConn
@@ -320,8 +326,8 @@ func (c *conn) Invoke(
return c.wrapError(err)
}
- c.touchLastUsage()
- defer c.touchLastUsage()
+ stop := c.lastUsage.Start()
+ defer stop()
ctx, traceID, err := meta.TraceID(ctx)
if err != nil {
@@ -332,6 +338,10 @@ func (c *conn) Invoke(
err = cc.Invoke(ctx, method, req, res, append(opts, grpc.Trailer(&md))...)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
defer func() {
c.onTransportError(ctx, err)
}()
@@ -344,6 +354,7 @@ func (c *conn) Invoke(
if sentMark.canRetry() {
return c.wrapError(xerrors.Retryable(err, xerrors.WithName("Invoke")))
}
+
return c.wrapError(err)
}
@@ -382,9 +393,9 @@ func (c *conn) NewStream(
opts ...grpc.CallOption,
) (_ grpc.ClientStream, err error) {
var (
- streamRecv = trace.DriverOnConnNewStream(
+ onDone = trace.DriverOnConnNewStream(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).NewStream"),
c.endpoint.Copy(), trace.Method(method),
)
useWrapping = UseWrapping(ctx)
@@ -393,18 +404,7 @@ func (c *conn) NewStream(
)
defer func() {
- if err != nil {
- streamRecv(err)(err, c.GetState(), metadata.MD{})
- }
- }()
-
- var cancel context.CancelFunc
- ctx, cancel = xcontext.WithCancel(ctx)
-
- defer func() {
- if err != nil {
- cancel()
- }
+ onDone(err, c.GetState())
}()
cc, err = c.realConn(ctx)
@@ -412,8 +412,8 @@ func (c *conn) NewStream(
return nil, c.wrapError(err)
}
- c.touchLastUsage()
- defer c.touchLastUsage()
+ stop := c.lastUsage.Start()
+ defer stop()
ctx, traceID, err := meta.TraceID(ctx)
if err != nil {
@@ -424,6 +424,10 @@ func (c *conn) NewStream(
s, err = cc.NewStream(ctx, desc, method, opts...)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
defer func() {
c.onTransportError(ctx, err)
}()
@@ -436,6 +440,7 @@ func (c *conn) NewStream(
if sentMark.canRetry() {
return s, c.wrapError(xerrors.Retryable(err, xerrors.WithName("NewStream")))
}
+
return s, c.wrapError(err)
}
@@ -444,15 +449,14 @@ func (c *conn) NewStream(
return &grpcClientStream{
ClientStream: s,
+ ctx: ctx,
c: c,
wrapping: useWrapping,
traceID: traceID,
sentMark: sentMark,
onDone: func(ctx context.Context, md metadata.MD) {
- cancel()
meta.CallTrailerCallback(ctx, md)
},
- recv: streamRecv,
}, nil
}
@@ -461,6 +465,7 @@ func (c *conn) wrapError(err error) error {
return nil
}
nodeErr := newConnError(c.endpoint.NodeID(), c.endpoint.Address(), err)
+
return xerrors.WithStackTrace(nodeErr, xerrors.WithSkipDepth(1))
}
@@ -484,14 +489,15 @@ func withOnTransportError(onTransportError func(ctx context.Context, cc Conn, ca
func newConn(e endpoint.Endpoint, config Config, opts ...option) *conn {
c := &conn{
- endpoint: e,
- config: config,
- done: make(chan struct{}),
+ endpoint: e,
+ config: config,
+ done: make(chan struct{}),
+ lastUsage: newLastUsage(nil),
}
c.state.Store(uint32(Created))
- for _, o := range opts {
- if o != nil {
- o(c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(c)
}
}
@@ -530,6 +536,7 @@ var rpcKey = ctxHandleRPCKey{}
func markContext(ctx context.Context) (context.Context, *modificationMark) {
mark := &modificationMark{}
+
return context.WithValue(ctx, rpcKey, mark), mark
}
@@ -538,11 +545,12 @@ func getContextMark(ctx context.Context) *modificationMark {
if v == nil {
return &modificationMark{}
}
+
return v.(*modificationMark)
}
type modificationMark struct {
- dirty xatomic.Bool
+ dirty atomic.Bool
}
func (m *modificationMark) canRetry() bool {
diff --git a/internal/conn/context.go b/internal/conn/context.go
index 927d1c846..64ffd877e 100644
--- a/internal/conn/context.go
+++ b/internal/conn/context.go
@@ -10,5 +10,6 @@ func WithoutWrapping(ctx context.Context) context.Context {
func UseWrapping(ctx context.Context) bool {
b, ok := ctx.Value(ctxNoWrappingKey{}).(bool)
+
return !ok || !b
}
diff --git a/internal/conn/error_test.go b/internal/conn/error_test.go
index cd9e68b71..569a38a31 100644
--- a/internal/conn/error_test.go
+++ b/internal/conn/error_test.go
@@ -32,30 +32,30 @@ func TestNodeErrorIs(t *testing.T) {
require.NotErrorIs(t, nodeErr, testErr2)
}
-type testErrorType1 struct {
+type testType1Error struct {
msg string
}
-func (t testErrorType1) Error() string {
+func (t testType1Error) Error() string {
return "1 - " + t.msg
}
-type testErrorType2 struct {
+type testType2Error struct {
msg string
}
-func (t testErrorType2) Error() string {
+func (t testType2Error) Error() string {
return "2 - " + t.msg
}
func TestNodeErrorAs(t *testing.T) {
- testErr := testErrorType1{msg: "test"}
+ testErr := testType1Error{msg: "test"}
nodeErr := newConnError(1, "localhost:1234", testErr)
- target := testErrorType1{}
+ target := testType1Error{}
require.ErrorAs(t, nodeErr, &target)
require.Equal(t, testErr, target)
- target2 := testErrorType2{}
+ target2 := testType2Error{}
require.False(t, errors.As(nodeErr, &target2))
}
diff --git a/internal/conn/grpc_client_stream.go b/internal/conn/grpc_client_stream.go
index a24db653e..32377e5ab 100644
--- a/internal/conn/grpc_client_stream.go
+++ b/internal/conn/grpc_client_stream.go
@@ -3,32 +3,45 @@ package conn
import (
"context"
"io"
- "time"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/wrap"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
type grpcClientStream struct {
grpc.ClientStream
+ ctx context.Context
c *conn
wrapping bool
traceID string
sentMark *modificationMark
onDone func(ctx context.Context, md metadata.MD)
- recv func(error) func(error, trace.ConnState, map[string][]string)
}
func (s *grpcClientStream) CloseSend() (err error) {
+ onDone := trace.DriverOnConnStreamCloseSend(s.c.config.Trace(), &s.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*grpcClientStream).CloseSend"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ stop := s.c.lastUsage.Start()
+ defer stop()
+
err = s.ClientStream.CloseSend()
if err != nil {
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
if s.wrapping {
return s.wrapError(
xerrors.Transport(
@@ -38,6 +51,7 @@ func (s *grpcClientStream) CloseSend() (err error) {
),
)
}
+
return s.wrapError(err)
}
@@ -45,12 +59,23 @@ func (s *grpcClientStream) CloseSend() (err error) {
}
func (s *grpcClientStream) SendMsg(m interface{}) (err error) {
- cancel := createPinger(s.c)
- defer cancel()
+ onDone := trace.DriverOnConnStreamSendMsg(s.c.config.Trace(), &s.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*grpcClientStream).SendMsg"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ stop := s.c.lastUsage.Start()
+ defer stop()
err = s.ClientStream.SendMsg(m)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
defer func() {
s.c.onTransportError(s.Context(), err)
}()
@@ -65,6 +90,7 @@ func (s *grpcClientStream) SendMsg(m interface{}) (err error) {
xerrors.WithName("SendMsg"),
))
}
+
return s.wrapError(err)
}
@@ -75,21 +101,30 @@ func (s *grpcClientStream) SendMsg(m interface{}) (err error) {
}
func (s *grpcClientStream) RecvMsg(m interface{}) (err error) {
- cancel := createPinger(s.c)
- defer cancel()
+ onDone := trace.DriverOnConnStreamRecvMsg(s.c.config.Trace(), &s.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*grpcClientStream).RecvMsg"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ stop := s.c.lastUsage.Start()
+ defer stop()
defer func() {
- onDone := s.recv(xerrors.HideEOF(err))
if err != nil {
md := s.ClientStream.Trailer()
- onDone(xerrors.HideEOF(err), s.c.GetState(), md)
- s.onDone(s.ClientStream.Context(), md)
+ s.onDone(s.ctx, md)
}
}()
err = s.ClientStream.RecvMsg(m)
- if err != nil {
+ if err != nil { //nolint:nestif
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
defer func() {
if !xerrors.Is(err, io.EOF) {
s.c.onTransportError(s.Context(), err)
@@ -105,6 +140,7 @@ func (s *grpcClientStream) RecvMsg(m interface{}) (err error) {
xerrors.WithName("RecvMsg"),
))
}
+
return s.wrapError(err)
}
@@ -132,26 +168,8 @@ func (s *grpcClientStream) wrapError(err error) error {
return nil
}
- nodeErr := newConnError(s.c.endpoint.NodeID(), s.c.endpoint.Address(), err)
- return xerrors.WithStackTrace(nodeErr, xerrors.WithSkipDepth(1))
-}
-
-func createPinger(c *conn) context.CancelFunc {
- c.touchLastUsage()
- ctx, cancel := xcontext.WithCancel(context.Background())
- go func() {
- ticker := time.NewTicker(time.Second)
- ctxDone := ctx.Done()
- for {
- select {
- case <-ctxDone:
- ticker.Stop()
- return
- case <-ticker.C:
- c.touchLastUsage()
- }
- }
- }()
-
- return cancel
+ return xerrors.WithStackTrace(
+ newConnError(s.c.endpoint.NodeID(), s.c.endpoint.Address(), err),
+ xerrors.WithSkipDepth(1),
+ )
}
diff --git a/internal/conn/last_usage.go b/internal/conn/last_usage.go
new file mode 100644
index 000000000..b0ca293a9
--- /dev/null
+++ b/internal/conn/last_usage.go
@@ -0,0 +1,47 @@
+package conn
+
+import (
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/jonboulle/clockwork"
+)
+
+type lastUsage struct {
+ locks atomic.Int64
+ t atomic.Pointer[time.Time]
+ clock clockwork.Clock
+}
+
+func newLastUsage(clock clockwork.Clock) *lastUsage {
+ if clock == nil {
+ clock = clockwork.NewRealClock()
+ }
+ now := clock.Now()
+ usage := &lastUsage{
+ clock: clock,
+ }
+ usage.t.Store(&now)
+
+ return usage
+}
+
+func (l *lastUsage) Get() time.Time {
+ if l.locks.Load() == 0 {
+ return *l.t.Load()
+ }
+
+ return l.clock.Now()
+}
+
+func (l *lastUsage) Start() (stop func()) {
+ l.locks.Add(1)
+
+ return sync.OnceFunc(func() {
+ if l.locks.Add(-1) == 0 {
+ now := l.clock.Now()
+ l.t.Store(&now)
+ }
+ })
+}
diff --git a/internal/conn/last_usage_test.go b/internal/conn/last_usage_test.go
new file mode 100644
index 000000000..b7c79695e
--- /dev/null
+++ b/internal/conn/last_usage_test.go
@@ -0,0 +1,98 @@
+package conn
+
+import (
+ "testing"
+ "time"
+
+ "github.com/jonboulle/clockwork"
+ "github.com/stretchr/testify/require"
+)
+
+func Test_lastUsage_Lock(t *testing.T) {
+ t.Run("NowFromLocked", func(t *testing.T) {
+ start := time.Unix(0, 0)
+ clock := clockwork.NewFakeClockAt(start)
+ lu := &lastUsage{
+ clock: clock,
+ }
+ lu.t.Store(&start)
+ t1 := lu.Get()
+ require.Equal(t, start, t1)
+ f := lu.Start()
+ clock.Advance(time.Hour)
+ t2 := lu.Get()
+ require.Equal(t, start.Add(time.Hour), t2)
+ clock.Advance(time.Hour)
+ f()
+ t3 := lu.Get()
+ require.Equal(t, start.Add(2*time.Hour), t3)
+ clock.Advance(time.Hour)
+ t4 := lu.Get()
+ require.Equal(t, start.Add(2*time.Hour), t4)
+ })
+ t.Run("UpdateAfterLastUnlock", func(t *testing.T) {
+ start := time.Unix(0, 0)
+ clock := clockwork.NewFakeClockAt(start)
+ lu := &lastUsage{
+ clock: clock,
+ }
+ lu.t.Store(&start)
+ t1 := lu.Get()
+ require.Equal(t, start, t1)
+ f1 := lu.Start()
+ clock.Advance(time.Hour)
+ t2 := lu.Get()
+ require.Equal(t, start.Add(time.Hour), t2)
+ f2 := lu.Start()
+ clock.Advance(time.Hour)
+ f1()
+ f3 := lu.Start()
+ clock.Advance(time.Hour)
+ t3 := lu.Get()
+ require.Equal(t, start.Add(3*time.Hour), t3)
+ clock.Advance(time.Hour)
+ t4 := lu.Get()
+ require.Equal(t, start.Add(4*time.Hour), t4)
+ f3()
+ t5 := lu.Get()
+ require.Equal(t, start.Add(4*time.Hour), t5)
+ clock.Advance(time.Hour)
+ t6 := lu.Get()
+ require.Equal(t, start.Add(5*time.Hour), t6)
+ clock.Advance(time.Hour)
+ f2()
+ t7 := lu.Get()
+ require.Equal(t, start.Add(6*time.Hour), t7)
+ clock.Advance(time.Hour)
+ f2()
+ t8 := lu.Get()
+ require.Equal(t, start.Add(6*time.Hour), t8)
+ })
+ t.Run("DeferRelease", func(t *testing.T) {
+ start := time.Unix(0, 0)
+ clock := clockwork.NewFakeClockAt(start)
+ lu := &lastUsage{
+ clock: clock,
+ }
+ lu.t.Store(&start)
+
+ func() {
+ t1 := lu.Get()
+ require.Equal(t, start, t1)
+ clock.Advance(time.Hour)
+ t2 := lu.Get()
+ require.Equal(t, start, t2)
+ clock.Advance(time.Hour)
+ defer lu.Start()()
+ t3 := lu.Get()
+ require.Equal(t, start.Add(2*time.Hour), t3)
+ clock.Advance(time.Hour)
+ t4 := lu.Get()
+ require.Equal(t, start.Add(3*time.Hour), t4)
+ clock.Advance(time.Hour)
+ }()
+ clock.Advance(time.Hour)
+ t5 := lu.Get()
+ require.Equal(t, start.Add(4*time.Hour), t5)
+ })
+}
diff --git a/internal/conn/middleware.go b/internal/conn/middleware.go
index f6069def8..07ab761e4 100644
--- a/internal/conn/middleware.go
+++ b/internal/conn/middleware.go
@@ -37,12 +37,14 @@ func WithContextModifier(
return &middleware{
invoke: func(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error {
ctx = modifyCtx(ctx)
+
return cc.Invoke(ctx, method, args, reply, opts...)
},
newStream: func(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (
grpc.ClientStream, error,
) {
ctx = modifyCtx(ctx)
+
return cc.NewStream(ctx, desc, method, opts...)
},
}
@@ -52,12 +54,14 @@ func WithAppendOptions(cc grpc.ClientConnInterface, appendOpts ...grpc.CallOptio
return &middleware{
invoke: func(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error {
opts = append(opts, appendOpts...)
+
return cc.Invoke(ctx, method, args, reply, opts...)
},
newStream: func(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (
grpc.ClientStream, error,
) {
opts = append(opts, appendOpts...)
+
return cc.NewStream(ctx, desc, method, opts...)
},
}
@@ -70,12 +74,14 @@ func WithBeforeFunc(
return &middleware{
invoke: func(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error {
before()
+
return cc.Invoke(ctx, method, args, reply, opts...)
},
newStream: func(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (
grpc.ClientStream, error,
) {
before()
+
return cc.NewStream(ctx, desc, method, opts...)
},
}
diff --git a/internal/conn/pool.go b/internal/conn/pool.go
index 47e0082e8..6115c612f 100644
--- a/internal/conn/pool.go
+++ b/internal/conn/pool.go
@@ -7,6 +7,7 @@ import (
"time"
"google.golang.org/grpc"
+ grpcCodes "google.golang.org/grpc/codes"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/endpoint"
@@ -79,6 +80,28 @@ func (p *Pool) Ban(ctx context.Context, cc Conn, cause error) {
return
}
+ if !xerrors.IsTransportError(cause,
+ grpcCodes.ResourceExhausted,
+ grpcCodes.Unavailable,
+ // grpcCodes.OK,
+ // grpcCodes.Canceled,
+ // grpcCodes.Unknown,
+ // grpcCodes.InvalidArgument,
+ // grpcCodes.DeadlineExceeded,
+ // grpcCodes.NotFound,
+ // grpcCodes.AlreadyExists,
+ // grpcCodes.PermissionDenied,
+ // grpcCodes.FailedPrecondition,
+ // grpcCodes.Aborted,
+ // grpcCodes.OutOfRange,
+ // grpcCodes.Unimplemented,
+ // grpcCodes.Internal,
+ // grpcCodes.DataLoss,
+ // grpcCodes.Unauthenticated,
+ ) {
+ return
+ }
+
e := cc.Endpoint().Copy()
p.mtx.RLock()
@@ -91,7 +114,7 @@ func (p *Pool) Ban(ctx context.Context, cc Conn, cause error) {
trace.DriverOnConnBan(
p.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*Pool).Ban"),
e, cc.GetState(), cause,
)(cc.SetState(ctx, Banned))
}
@@ -113,18 +136,21 @@ func (p *Pool) Allow(ctx context.Context, cc Conn) {
trace.DriverOnConnAllow(
p.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*Pool).Allow"),
e, cc.GetState(),
)(cc.Unban(ctx))
}
func (p *Pool) Take(context.Context) error {
atomic.AddInt64(&p.usages, 1)
+
return nil
}
func (p *Pool) Release(ctx context.Context) (finalErr error) {
- onDone := trace.DriverOnPoolRelease(p.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnPoolRelease(p.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*Pool).Release"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -201,11 +227,14 @@ func (p *Pool) collectConns() []*conn {
for _, c := range p.conns {
conns = append(conns, c)
}
+
return conns
}
func NewPool(ctx context.Context, config Config) *Pool {
- onDone := trace.DriverOnPoolNew(config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnPoolNew(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.NewPool"),
+ )
defer onDone()
p := &Pool{
@@ -215,8 +244,10 @@ func NewPool(ctx context.Context, config Config) *Pool {
conns: make(map[connsKey]*conn),
done: make(chan struct{}),
}
+
if ttl := config.ConnectionTTL(); ttl > 0 {
- go p.connParker(xcontext.WithoutDeadline(ctx), ttl, ttl/2)
+ go p.connParker(xcontext.ValueOnly(ctx), ttl, ttl/2)
}
+
return p
}
diff --git a/internal/coordination/client.go b/internal/coordination/client.go
index 078054732..0bb225f67 100644
--- a/internal/coordination/client.go
+++ b/internal/coordination/client.go
@@ -33,12 +33,12 @@ type Client struct {
sessions map[*session]struct{}
}
-func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) (*Client, error) {
+func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) *Client {
return &Client{
config: config,
service: Ydb_Coordination_V1.NewCoordinationServiceClient(cc),
sessions: make(map[*session]struct{}),
- }, nil
+ }
}
func (c *Client) CreateNode(ctx context.Context, path string, config coordination.NodeConfig) error {
@@ -51,6 +51,7 @@ func (c *Client) CreateNode(ctx context.Context, path string, config coordinatio
if !c.config.AutoRetry() {
return xerrors.WithStackTrace(call(ctx))
}
+
return retry.Retry(ctx,
call, retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -79,6 +80,7 @@ func (c *Client) createNode(ctx context.Context, path string, config coordinatio
),
},
)
+
return xerrors.WithStackTrace(err)
}
@@ -92,6 +94,7 @@ func (c *Client) AlterNode(ctx context.Context, path string, config coordination
if !c.config.AutoRetry() {
return xerrors.WithStackTrace(call(ctx))
}
+
return retry.Retry(ctx,
call,
retry.WithStackTrace(),
@@ -121,6 +124,7 @@ func (c *Client) alterNode(ctx context.Context, path string, config coordination
),
},
)
+
return xerrors.WithStackTrace(err)
}
@@ -134,6 +138,7 @@ func (c *Client) DropNode(ctx context.Context, path string) error {
if !c.config.AutoRetry() {
return xerrors.WithStackTrace(call(ctx))
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -154,6 +159,7 @@ func (c *Client) dropNode(ctx context.Context, path string) error {
),
},
)
+
return xerrors.WithStackTrace(err)
}
@@ -170,10 +176,12 @@ func (c *Client) DescribeNode(
}
call := func(ctx context.Context) (err error) {
entry, config, err = c.describeNode(ctx, path)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err := call(ctx)
+
return entry, config, xerrors.WithStackTrace(err)
}
err := retry.Retry(ctx, call,
@@ -181,6 +189,7 @@ func (c *Client) DescribeNode(
retry.WithIdempotent(true),
retry.WithTrace(c.config.TraceRetry()),
)
+
return entry, config, xerrors.WithStackTrace(err)
}
@@ -216,6 +225,7 @@ func (c *Client) describeNode(
if err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
+
return scheme.InnerConvertEntry(result.GetSelf()), &coordination.NodeConfig{
Path: result.GetConfig().GetPath(),
SelfCheckPeriodMillis: result.GetConfig().GetSelfCheckPeriodMillis(),
diff --git a/internal/coordination/config/config.go b/internal/coordination/config/config.go
index c3c21dddc..692777a43 100644
--- a/internal/coordination/config/config.go
+++ b/internal/coordination/config/config.go
@@ -6,8 +6,6 @@ import (
)
// Config is an configuration of coordination client
-//
-//nolint:maligned
type Config struct {
config.Common
@@ -39,10 +37,11 @@ func New(opts ...Option) Config {
c := Config{
trace: &trace.Coordination{},
}
- for _, o := range opts {
- if o != nil {
- o(&c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&c)
}
}
+
return c
}
diff --git a/internal/credentials/access_error.go b/internal/credentials/access_error.go
index ce904e2e4..777bc3d80 100644
--- a/internal/credentials/access_error.go
+++ b/internal/credentials/access_error.go
@@ -94,12 +94,15 @@ func AccessError(msg string, err error, opts ...authErrorOption) error {
buffer.WriteString(msg)
buffer.WriteString(" (")
for i, opt := range opts {
- if i != 0 {
- buffer.WriteString(",")
+ if opt != nil {
+ if i != 0 {
+ buffer.WriteString(",")
+ }
+ opt.applyAuthErrorOption(buffer)
}
- opt.applyAuthErrorOption(buffer)
}
buffer.WriteString("): %w")
+
return xerrors.WithStackTrace(fmt.Errorf(buffer.String(), err), xerrors.WithSkipDepth(1))
}
@@ -115,5 +118,6 @@ func IsAccessError(err error) bool {
) {
return true
}
+
return false
}
diff --git a/internal/credentials/access_token.go b/internal/credentials/access_token.go
index 57e0f12bc..c6e205f32 100644
--- a/internal/credentials/access_token.go
+++ b/internal/credentials/access_token.go
@@ -32,8 +32,11 @@ func NewAccessTokenCredentials(token string, opts ...AccessTokenCredentialsOptio
sourceInfo: stack.Record(1),
}
for _, opt := range opts {
- opt.ApplyAccessTokenCredentialsOption(c)
+ if opt != nil {
+ opt.ApplyAccessTokenCredentialsOption(c)
+ }
}
+
return c
}
@@ -53,5 +56,6 @@ func (c AccessToken) String() string {
fmt.Fprintf(buffer, "%q", c.sourceInfo)
}
buffer.WriteByte('}')
+
return buffer.String()
}
diff --git a/internal/credentials/anonymous.go b/internal/credentials/anonymous.go
index eea7ba2c1..88d937095 100644
--- a/internal/credentials/anonymous.go
+++ b/internal/credentials/anonymous.go
@@ -28,8 +28,11 @@ func NewAnonymousCredentials(opts ...AnonymousCredentialsOption) *Anonymous {
sourceInfo: stack.Record(1),
}
for _, opt := range opts {
- opt.ApplyAnonymousCredentialsOption(c)
+ if opt != nil {
+ opt.ApplyAnonymousCredentialsOption(c)
+ }
}
+
return c
}
@@ -48,5 +51,6 @@ func (c Anonymous) String() string {
fmt.Fprintf(buffer, "%q", c.sourceInfo)
}
buffer.WriteByte('}')
+
return buffer.String()
}
diff --git a/internal/credentials/static.go b/internal/credentials/static.go
index 39bba0234..298785bf1 100644
--- a/internal/credentials/static.go
+++ b/internal/credentials/static.go
@@ -47,8 +47,11 @@ func NewStaticCredentials(user, password, endpoint string, opts ...StaticCredent
sourceInfo: stack.Record(1),
}
for _, opt := range opts {
- opt.ApplyStaticCredentialsOption(c)
+ if opt != nil {
+ opt.ApplyStaticCredentialsOption(c)
+ }
}
+
return c
}
@@ -141,6 +144,7 @@ func parseExpiresAt(raw string) (expiresAt time.Time, err error) {
if _, _, err = jwt.NewParser().ParseUnverified(raw, &claims); err != nil {
return expiresAt, xerrors.WithStackTrace(err)
}
+
return claims.ExpiresAt.Time, nil
}
@@ -158,5 +162,6 @@ func (c *Static) String() string {
fmt.Fprintf(buffer, "%q", c.sourceInfo)
}
buffer.WriteByte('}')
+
return buffer.String()
}
diff --git a/internal/decimal/decimal.go b/internal/decimal/decimal.go
index 4bf91f6ab..a4753992a 100644
--- a/internal/decimal/decimal.go
+++ b/internal/decimal/decimal.go
@@ -73,6 +73,7 @@ func FromBytes(bts []byte, precision, scale uint32) *big.Int {
v.Set(inf)
}
}
+
return v
}
@@ -102,12 +103,14 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
if neg {
return v.Set(neginf), nil
}
+
return v.Set(inf), nil
}
if isNaN(s) {
if neg {
return v.Set(negnan), nil
}
+
return v.Set(nan), nil
}
@@ -121,6 +124,7 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
return nil, syntaxError(s)
}
dot = true
+
continue
}
if dot {
@@ -142,6 +146,7 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
if neg {
return neginf, nil
}
+
return inf, nil
}
integral--
@@ -176,6 +181,7 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
if neg {
v.Neg(v)
}
+
return v, nil
}
@@ -187,12 +193,14 @@ func Format(x *big.Int, precision, scale uint32) string {
if x.Sign() < 0 {
return "-inf"
}
+
return "inf"
case x.CmpAbs(nan) == 0:
if x.Sign() < 0 {
return "-nan"
}
+
return "nan"
case x == nil:
@@ -271,6 +279,7 @@ func BigIntToByte(x *big.Int, precision, scale uint32) (p [16]byte) {
}
}
put(x, p[:])
+
return p
}
@@ -301,6 +310,7 @@ func Append(p []byte, x *big.Int) []byte {
n := len(p)
p = ensure(p, size(x))
put(x, p[n:])
+
return p
}
@@ -308,6 +318,7 @@ func size(x *big.Int) int {
if x.Sign() < 0 {
x = complement(x)
}
+
return len(x.Bits()) * wordSize
}
@@ -321,6 +332,7 @@ func ensure(p []byte, n int) []byte {
copy(cp, p)
p = cp
}
+
return p[:l+n]
}
@@ -346,6 +358,7 @@ func pow(x *big.Int, n uint32) *big.Int {
n >>= 1
m.Mul(m, m)
}
+
return v
}
@@ -356,6 +369,7 @@ func complement(x *big.Int) *big.Int {
not(x)
x.Neg(x)
x.Add(x, one)
+
return x
}
diff --git a/internal/decimal/decimal_test.go b/internal/decimal/decimal_test.go
index 8178c37c9..fd7391da1 100644
--- a/internal/decimal/decimal_test.go
+++ b/internal/decimal/decimal_test.go
@@ -61,6 +61,7 @@ func uint128(hi, lo uint64) []byte {
p := make([]byte, 16)
binary.BigEndian.PutUint64(p[:8], hi)
binary.BigEndian.PutUint64(p[8:], lo)
+
return p
}
diff --git a/internal/decimal/type.go b/internal/decimal/type.go
new file mode 100644
index 000000000..89956a761
--- /dev/null
+++ b/internal/decimal/type.go
@@ -0,0 +1,19 @@
+package decimal
+
+import "math/big"
+
+type Decimal struct {
+ Bytes [16]byte
+ Precision uint32
+ Scale uint32
+}
+
+func (d *Decimal) String() string {
+ v := FromInt128(d.Bytes, d.Precision, d.Scale)
+
+ return Format(v, d.Precision, d.Scale)
+}
+
+func (d *Decimal) BigInt() *big.Int {
+ return FromInt128(d.Bytes, d.Precision, d.Scale)
+}
diff --git a/internal/discovery/config/config.go b/internal/discovery/config/config.go
index ebcdce783..782f3b6b2 100644
--- a/internal/discovery/config/config.go
+++ b/internal/discovery/config/config.go
@@ -29,11 +29,12 @@ func New(opts ...Option) *Config {
interval: DefaultInterval,
trace: &trace.Discovery{},
}
- for _, o := range opts {
- if o != nil {
- o(c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(c)
}
}
+
return c
}
diff --git a/internal/discovery/discovery.go b/internal/discovery/discovery.go
index 6126c5961..dfda2660c 100644
--- a/internal/discovery/discovery.go
+++ b/internal/discovery/discovery.go
@@ -19,12 +19,12 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
-func New(ctx context.Context, cc grpc.ClientConnInterface, config *config.Config) (*Client, error) {
+func New(ctx context.Context, cc grpc.ClientConnInterface, config *config.Config) *Client {
return &Client{
config: config,
cc: cc,
client: Ydb_Discovery_V1.NewDiscoveryServiceClient(cc),
- }, nil
+ }
}
var _ discovery.Client = &Client{}
@@ -40,7 +40,7 @@ func (c *Client) Discover(ctx context.Context) (endpoints []endpoint.Endpoint, e
var (
onDone = trace.DiscoveryOnDiscover(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/discovery.(*Client).Discover"),
c.config.Endpoint(), c.config.Database(),
)
request = Ydb_Discovery.ListEndpointsRequest{
@@ -70,9 +70,7 @@ func (c *Client) Discover(ctx context.Context) (endpoints []endpoint.Endpoint, e
if response.GetOperation().GetStatus() != Ydb.StatusIds_SUCCESS {
return nil, xerrors.WithStackTrace(
- xerrors.Operation(
- xerrors.FromOperation(response.GetOperation()),
- ),
+ xerrors.FromOperation(response.GetOperation()),
)
}
@@ -82,9 +80,9 @@ func (c *Client) Discover(ctx context.Context) (endpoints []endpoint.Endpoint, e
}
location = result.GetSelfLocation()
- endpoints = make([]endpoint.Endpoint, 0, len(result.Endpoints))
- for _, e := range result.Endpoints {
- if e.Ssl == c.config.Secure() {
+ endpoints = make([]endpoint.Endpoint, 0, len(result.GetEndpoints()))
+ for _, e := range result.GetEndpoints() {
+ if e.GetSsl() == c.config.Secure() {
endpoints = append(endpoints, endpoint.New(
net.JoinHostPort(e.GetAddress(), strconv.Itoa(int(e.GetPort()))),
endpoint.WithLocation(e.GetLocation()),
@@ -101,7 +99,9 @@ func (c *Client) Discover(ctx context.Context) (endpoints []endpoint.Endpoint, e
func (c *Client) WhoAmI(ctx context.Context) (whoAmI *discovery.WhoAmI, err error) {
var (
- onDone = trace.DiscoveryOnWhoAmI(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone = trace.DiscoveryOnWhoAmI(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/discovery.(*Client).WhoAmI"),
+ )
request = Ydb_Discovery.WhoAmIRequest{}
response *Ydb_Discovery.WhoAmIResponse
whoAmIResultResult Ydb_Discovery.WhoAmIResult
@@ -126,10 +126,8 @@ func (c *Client) WhoAmI(ctx context.Context) (whoAmI *discovery.WhoAmI, err erro
if response.GetOperation().GetStatus() != Ydb.StatusIds_SUCCESS {
return nil, xerrors.WithStackTrace(
- xerrors.Operation(
- xerrors.FromOperation(
- response.GetOperation(),
- ),
+ xerrors.FromOperation(
+ response.GetOperation(),
),
)
}
@@ -154,5 +152,6 @@ func (c *Client) Close(context.Context) error {
if cc, has := c.cc.(io.Closer); has {
return cc.Close()
}
+
return nil
}
diff --git a/internal/endpoint/endpoint.go b/internal/endpoint/endpoint.go
index 139829cac..823d721d0 100644
--- a/internal/endpoint/endpoint.go
+++ b/internal/endpoint/endpoint.go
@@ -39,6 +39,7 @@ type endpoint struct {
func (e *endpoint) Copy() Endpoint {
e.mu.RLock()
defer e.mu.RUnlock()
+
return &endpoint{
id: e.id,
address: e.address,
@@ -53,6 +54,7 @@ func (e *endpoint) Copy() Endpoint {
func (e *endpoint) String() string {
e.mu.RLock()
defer e.mu.RUnlock()
+
return fmt.Sprintf(`{id:%d,address:%q,local:%t,location:%q,loadFactor:%f,lastUpdated:%q}`,
e.id,
e.address,
@@ -66,49 +68,52 @@ func (e *endpoint) String() string {
func (e *endpoint) NodeID() uint32 {
e.mu.RLock()
defer e.mu.RUnlock()
+
return e.id
}
func (e *endpoint) Address() (address string) {
e.mu.RLock()
defer e.mu.RUnlock()
+
return e.address
}
func (e *endpoint) Location() string {
e.mu.RLock()
defer e.mu.RUnlock()
+
return e.location
}
func (e *endpoint) LocalDC() bool {
e.mu.RLock()
defer e.mu.RUnlock()
+
return e.local
}
func (e *endpoint) LoadFactor() float32 {
e.mu.RLock()
defer e.mu.RUnlock()
+
return e.loadFactor
}
func (e *endpoint) LastUpdated() time.Time {
e.mu.RLock()
defer e.mu.RUnlock()
+
return e.lastUpdated
}
func (e *endpoint) Touch(opts ...Option) {
e.mu.Lock()
defer e.mu.Unlock()
- for _, o := range append(
- []Option{
- withLastUpdated(time.Now()),
- },
- opts...,
- ) {
- o(e)
+ for _, opt := range append([]Option{withLastUpdated(time.Now())}, opts...) {
+ if opt != nil {
+ opt(e)
+ }
}
}
@@ -155,10 +160,11 @@ func New(address string, opts ...Option) *endpoint {
address: address,
lastUpdated: time.Now(),
}
- for _, o := range opts {
- if o != nil {
- o(e)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(e)
}
}
+
return e
}
diff --git a/internal/grpcwrapper/rawoptional/rawoptional.go b/internal/grpcwrapper/rawoptional/rawoptional.go
index aed976dfe..e4aec2c4a 100644
--- a/internal/grpcwrapper/rawoptional/rawoptional.go
+++ b/internal/grpcwrapper/rawoptional/rawoptional.go
@@ -18,6 +18,7 @@ func (b *Bool) ToProto() *bool {
}
val := b.Value
+
return &val
}
@@ -30,6 +31,7 @@ func (v *Duration) ToProto() *durationpb.Duration {
if v.HasValue {
return durationpb.New(v.Value)
}
+
return nil
}
@@ -44,6 +46,7 @@ func (v *Int64) ToProto() *int64 {
}
val := v.Value
+
return &val
}
@@ -56,6 +59,7 @@ func (v *Time) ToProto() *timestamppb.Timestamp {
if v.HasValue {
return timestamppb.New(v.Value)
}
+
return nil
}
@@ -63,6 +67,7 @@ func (v *Time) MustFromProto(proto *timestamppb.Timestamp) {
if proto == nil {
v.Value = time.Time{}
v.HasValue = false
+
return
}
diff --git a/internal/grpcwrapper/rawscheme/entry.go b/internal/grpcwrapper/rawscheme/entry.go
index e1516e6c3..f1fb68bde 100644
--- a/internal/grpcwrapper/rawscheme/entry.go
+++ b/internal/grpcwrapper/rawscheme/entry.go
@@ -26,25 +26,26 @@ func (e *Entry) FromProto(proto *Ydb_Scheme.Entry) error {
if proto == nil {
return xerrors.WithStackTrace(errUnexpectedNilForSchemeEntry)
}
- e.Name = proto.Name
- e.Owner = proto.Owner
- e.Type = EntryType(proto.Type)
+ e.Name = proto.GetName()
+ e.Owner = proto.GetOwner()
+ e.Type = EntryType(proto.GetType())
- e.EffectivePermissions = make([]Permissions, len(proto.EffectivePermissions))
- for i := range proto.EffectivePermissions {
- if err := e.EffectivePermissions[i].FromProto(proto.EffectivePermissions[i]); err != nil {
+ e.EffectivePermissions = make([]Permissions, len(proto.GetEffectivePermissions()))
+ for i := range proto.GetEffectivePermissions() {
+ if err := e.EffectivePermissions[i].FromProto(proto.GetEffectivePermissions()[i]); err != nil {
return err
}
}
- e.Permissions = make([]Permissions, len(proto.Permissions))
- for i := range proto.Permissions {
- if err := e.Permissions[i].FromProto(proto.Permissions[i]); err != nil {
+ e.Permissions = make([]Permissions, len(proto.GetPermissions()))
+ for i := range proto.GetPermissions() {
+ if err := e.Permissions[i].FromProto(proto.GetPermissions()[i]); err != nil {
return err
}
}
- e.SizeBytes = proto.SizeBytes
+ e.SizeBytes = proto.GetSizeBytes()
+
return nil
}
@@ -73,7 +74,8 @@ func (p *Permissions) FromProto(proto *Ydb_Scheme.Permissions) error {
if proto == nil {
return xerrors.WithStackTrace(errUnexpectedNilForSchemePermissions)
}
- p.Subject = proto.Subject
- p.PermissionNames = proto.PermissionNames
+ p.Subject = proto.GetSubject()
+ p.PermissionNames = proto.GetPermissionNames()
+
return nil
}
diff --git a/internal/grpcwrapper/rawtopic/alter_topic.go b/internal/grpcwrapper/rawtopic/alter_topic.go
index 125311e01..d7db57d74 100644
--- a/internal/grpcwrapper/rawtopic/alter_topic.go
+++ b/internal/grpcwrapper/rawtopic/alter_topic.go
@@ -64,7 +64,7 @@ type AlterTopicResult struct {
}
func (r *AlterTopicResult) FromProto(proto *Ydb_Topic.AlterTopicResponse) error {
- return r.Operation.FromProtoWithStatusCheck(proto.Operation)
+ return r.Operation.FromProtoWithStatusCheck(proto.GetOperation())
}
type AlterConsumer struct {
diff --git a/internal/grpcwrapper/rawtopic/client.go b/internal/grpcwrapper/rawtopic/client.go
index d5081bf80..5ccc30225 100644
--- a/internal/grpcwrapper/rawtopic/client.go
+++ b/internal/grpcwrapper/rawtopic/client.go
@@ -25,6 +25,7 @@ func (c *Client) AlterTopic(ctx context.Context, req *AlterTopicRequest) (res Al
return res, xerrors.WithStackTrace(fmt.Errorf("ydb: alter topic grpc failed: %w", err))
}
err = res.FromProto(resp)
+
return res, err
}
@@ -37,6 +38,7 @@ func (c *Client) CreateTopic(
return res, xerrors.WithStackTrace(fmt.Errorf("ydb: create topic grpc failed: %w", err))
}
err = res.FromProto(resp)
+
return res, err
}
@@ -48,6 +50,7 @@ func (c *Client) DescribeTopic(ctx context.Context, req DescribeTopicRequest) (r
))
}
err = res.FromProto(resp)
+
return res, err
}
@@ -60,6 +63,7 @@ func (c *Client) DropTopic(
return res, xerrors.WithStackTrace(fmt.Errorf("ydb: drop topic grpc failed: %w", err))
}
err = res.FromProto(resp)
+
return res, err
}
@@ -72,6 +76,7 @@ func (c *Client) StreamRead(ctxStreamLifeTime context.Context) (rawtopicreader.S
),
)
}
+
return rawtopicreader.StreamReader{Stream: protoResp}, nil
}
@@ -84,5 +89,6 @@ func (c *Client) StreamWrite(ctxStreamLifeTime context.Context) (*rawtopicwriter
),
)
}
+
return &rawtopicwriter.StreamWriter{Stream: protoResp}, nil
}
diff --git a/internal/grpcwrapper/rawtopic/controlplane_types.go b/internal/grpcwrapper/rawtopic/controlplane_types.go
index 8dfe43a6f..6df4322fb 100644
--- a/internal/grpcwrapper/rawtopic/controlplane_types.go
+++ b/internal/grpcwrapper/rawtopic/controlplane_types.go
@@ -25,7 +25,7 @@ func (c *Consumer) MustFromProto(consumer *Ydb_Topic.Consumer) {
c.Important = consumer.GetImportant()
c.Attributes = consumer.GetAttributes()
c.ReadFrom.MustFromProto(consumer.GetReadFrom())
- c.SupportedCodecs.MustFromProto(consumer.SupportedCodecs)
+ c.SupportedCodecs.MustFromProto(consumer.GetSupportedCodecs())
}
func (c *Consumer) ToProto() *Ydb_Topic.Consumer {
@@ -56,8 +56,9 @@ func (s *PartitioningSettings) FromProto(proto *Ydb_Topic.PartitioningSettings)
return xerrors.WithStackTrace(errUnexpectedNilPartitioningSettings)
}
- s.MinActivePartitions = proto.MinActivePartitions
- s.PartitionCountLimit = proto.PartitionCountLimit
+ s.MinActivePartitions = proto.GetMinActivePartitions()
+ s.PartitionCountLimit = proto.GetPartitionCountLimit()
+
return nil
}
diff --git a/internal/grpcwrapper/rawtopic/create_topic.go b/internal/grpcwrapper/rawtopic/create_topic.go
index f8ecb6980..fd17da84e 100644
--- a/internal/grpcwrapper/rawtopic/create_topic.go
+++ b/internal/grpcwrapper/rawtopic/create_topic.go
@@ -41,7 +41,7 @@ func (req *CreateTopicRequest) ToProto() *Ydb_Topic.CreateTopicRequest {
proto.Attributes = req.Attributes
proto.Consumers = make([]*Ydb_Topic.Consumer, len(req.Consumers))
- for i := range proto.Consumers {
+ for i := range proto.GetConsumers() {
proto.Consumers[i] = req.Consumers[i].ToProto()
}
@@ -55,5 +55,5 @@ type CreateTopicResult struct {
}
func (r *CreateTopicResult) FromProto(proto *Ydb_Topic.CreateTopicResponse) error {
- return r.Operation.FromProtoWithStatusCheck(proto.Operation)
+ return r.Operation.FromProtoWithStatusCheck(proto.GetOperation())
}
diff --git a/internal/grpcwrapper/rawtopic/describe_topic.go b/internal/grpcwrapper/rawtopic/describe_topic.go
index bca36dab5..a1c3d4838 100644
--- a/internal/grpcwrapper/rawtopic/describe_topic.go
+++ b/internal/grpcwrapper/rawtopic/describe_topic.go
@@ -42,8 +42,8 @@ type DescribeTopicResult struct {
}
func (res *DescribeTopicResult) FromProto(protoResponse *Ydb_Topic.DescribeTopicResponse) error {
- if err := res.Operation.FromProtoWithStatusCheck(protoResponse.Operation); err != nil {
- return nil
+ if err := res.Operation.FromProtoWithStatusCheck(protoResponse.GetOperation()); err != nil {
+ return err
}
protoResult := &Ydb_Topic.DescribeTopicResult{}
@@ -51,11 +51,11 @@ func (res *DescribeTopicResult) FromProto(protoResponse *Ydb_Topic.DescribeTopic
return xerrors.WithStackTrace(fmt.Errorf("ydb: describe topic result failed on unmarshal grpc result: %w", err))
}
- if err := res.Self.FromProto(protoResult.Self); err != nil {
+ if err := res.Self.FromProto(protoResult.GetSelf()); err != nil {
return err
}
- if err := res.PartitioningSettings.FromProto(protoResult.PartitioningSettings); err != nil {
+ if err := res.PartitioningSettings.FromProto(protoResult.GetPartitioningSettings()); err != nil {
return err
}
@@ -72,17 +72,17 @@ func (res *DescribeTopicResult) FromProto(protoResponse *Ydb_Topic.DescribeTopic
res.SupportedCodecs = append(res.SupportedCodecs, rawtopiccommon.Codec(v))
}
- res.PartitionWriteSpeedBytesPerSecond = protoResult.PartitionWriteSpeedBytesPerSecond
- res.PartitionWriteBurstBytes = protoResult.PartitionWriteBurstBytes
+ res.PartitionWriteSpeedBytesPerSecond = protoResult.GetPartitionWriteSpeedBytesPerSecond()
+ res.PartitionWriteBurstBytes = protoResult.GetPartitionWriteBurstBytes()
- res.Attributes = protoResult.Attributes
+ res.Attributes = protoResult.GetAttributes()
- res.Consumers = make([]Consumer, len(protoResult.Consumers))
+ res.Consumers = make([]Consumer, len(protoResult.GetConsumers()))
for i := range res.Consumers {
- res.Consumers[i].MustFromProto(protoResult.Consumers[i])
+ res.Consumers[i].MustFromProto(protoResult.GetConsumers()[i])
}
- res.MeteringMode = MeteringMode(protoResult.MeteringMode)
+ res.MeteringMode = MeteringMode(protoResult.GetMeteringMode())
return nil
}
diff --git a/internal/grpcwrapper/rawtopic/drop_topic.go b/internal/grpcwrapper/rawtopic/drop_topic.go
index 586284fa8..0db29973a 100644
--- a/internal/grpcwrapper/rawtopic/drop_topic.go
+++ b/internal/grpcwrapper/rawtopic/drop_topic.go
@@ -23,5 +23,5 @@ type DropTopicResult struct {
}
func (r *DropTopicResult) FromProto(proto *Ydb_Topic.DropTopicResponse) error {
- return r.Operation.FromProtoWithStatusCheck(proto.Operation)
+ return r.Operation.FromProtoWithStatusCheck(proto.GetOperation())
}
diff --git a/internal/grpcwrapper/rawtopic/rawtopiccommon/codec.go b/internal/grpcwrapper/rawtopic/rawtopiccommon/codec.go
index 70f622403..166818331 100644
--- a/internal/grpcwrapper/rawtopic/rawtopiccommon/codec.go
+++ b/internal/grpcwrapper/rawtopic/rawtopiccommon/codec.go
@@ -53,12 +53,14 @@ func (c *SupportedCodecs) Contains(need Codec) bool {
return true
}
}
+
return false
}
func (c *SupportedCodecs) Clone() SupportedCodecs {
res := make(SupportedCodecs, len(*c))
copy(res, *c)
+
return res
}
@@ -77,6 +79,7 @@ func (c *SupportedCodecs) IsEqualsTo(other SupportedCodecs) bool {
return false
}
}
+
return true
}
@@ -88,13 +91,14 @@ func (c *SupportedCodecs) ToProto() *Ydb_Topic.SupportedCodecs {
for i := range codecs {
proto.Codecs[i] = int32(codecs[i].ToProto().Number())
}
+
return proto
}
func (c *SupportedCodecs) MustFromProto(proto *Ydb_Topic.SupportedCodecs) {
res := make([]Codec, len(proto.GetCodecs()))
for i := range proto.GetCodecs() {
- res[i].MustFromProto(Ydb_Topic.Codec(proto.Codecs[i]))
+ res[i].MustFromProto(Ydb_Topic.Codec(proto.GetCodecs()[i]))
}
*c = res
}
diff --git a/internal/grpcwrapper/rawtopic/rawtopicreader/messages.go b/internal/grpcwrapper/rawtopic/rawtopicreader/messages.go
index a29d48f80..ad60427fa 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicreader/messages.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicreader/messages.go
@@ -72,8 +72,10 @@ func (offset OptionalOffset) ToInt64() int64 {
func (offset OptionalOffset) ToInt64Pointer() *int64 {
if offset.HasValue {
v := offset.Offset.ToInt64()
+
return &v
}
+
return nil
}
@@ -88,11 +90,11 @@ type UpdateTokenRequest struct {
}
type UpdateTokenResponse struct {
+ rawtopiccommon.UpdateTokenResponse
+
serverMessageImpl
rawtopiccommon.ServerMessageMetadata
-
- rawtopiccommon.UpdateTokenResponse
}
//
@@ -137,6 +139,7 @@ func (r *InitRequest) GetTopics() []string {
for i := range res {
res[i] = r.TopicsReadSettings[i].Path
}
+
return res
}
@@ -157,7 +160,7 @@ type InitResponse struct {
}
func (g *InitResponse) fromProto(p *Ydb_Topic.StreamReadMessage_InitResponse) {
- g.SessionID = p.SessionId
+ g.SessionID = p.GetSessionId()
}
//
@@ -198,6 +201,7 @@ func (r *ReadResponse) GetPartitionBatchMessagesCounts() (partitionDataCount, ba
messagesCount += len(partitionData.Batches[batchIndex].MessageData)
}
}
+
return partitionDataCount, batchCount, messagesCount
}
@@ -205,58 +209,59 @@ func (r *ReadResponse) fromProto(p *Ydb_Topic.StreamReadMessage_ReadResponse) er
if p == nil {
return xerrors.WithStackTrace(errUnexpectedNilStreamReadMessageReadResponse)
}
- r.BytesSize = int(p.BytesSize)
+ r.BytesSize = int(p.GetBytesSize())
- r.PartitionData = make([]PartitionData, len(p.PartitionData))
- for partitionIndex := range p.PartitionData {
- srcPartition := p.PartitionData[partitionIndex]
+ r.PartitionData = make([]PartitionData, len(p.GetPartitionData()))
+ for partitionIndex := range p.GetPartitionData() {
+ srcPartition := p.GetPartitionData()[partitionIndex]
if srcPartition == nil {
return xerrors.WithStackTrace(errNilPartitionData)
}
dstPartition := &r.PartitionData[partitionIndex]
- dstPartition.PartitionSessionID.FromInt64(srcPartition.PartitionSessionId)
+ dstPartition.PartitionSessionID.FromInt64(srcPartition.GetPartitionSessionId())
- dstPartition.Batches = make([]Batch, len(srcPartition.Batches))
+ dstPartition.Batches = make([]Batch, len(srcPartition.GetBatches()))
- for batchIndex := range srcPartition.Batches {
- srcBatch := srcPartition.Batches[batchIndex]
+ for batchIndex := range srcPartition.GetBatches() {
+ srcBatch := srcPartition.GetBatches()[batchIndex]
if srcBatch == nil {
return xerrors.WithStackTrace(errUnexpectedNilBatchInPartitionData)
}
dstBatch := &dstPartition.Batches[batchIndex]
- dstBatch.ProducerID = srcBatch.ProducerId
- dstBatch.WriteSessionMeta = srcBatch.WriteSessionMeta
- dstBatch.Codec.MustFromProto(Ydb_Topic.Codec(srcBatch.Codec))
+ dstBatch.ProducerID = srcBatch.GetProducerId()
+ dstBatch.WriteSessionMeta = srcBatch.GetWriteSessionMeta()
+ dstBatch.Codec.MustFromProto(Ydb_Topic.Codec(srcBatch.GetCodec()))
- dstBatch.WrittenAt = srcBatch.WrittenAt.AsTime()
+ dstBatch.WrittenAt = srcBatch.GetWrittenAt().AsTime()
- dstBatch.MessageData = make([]MessageData, len(srcBatch.MessageData))
- for messageIndex := range srcBatch.MessageData {
- srcMessage := srcBatch.MessageData[messageIndex]
+ dstBatch.MessageData = make([]MessageData, len(srcBatch.GetMessageData()))
+ for messageIndex := range srcBatch.GetMessageData() {
+ srcMessage := srcBatch.GetMessageData()[messageIndex]
if srcMessage == nil {
return xerrors.WithStackTrace(errUnexpectedMessageNilInPartitionData)
}
dstMessage := &dstBatch.MessageData[messageIndex]
- dstMessage.Offset.FromInt64(srcMessage.Offset)
- dstMessage.SeqNo = srcMessage.SeqNo
- dstMessage.CreatedAt = srcMessage.CreatedAt.AsTime()
- dstMessage.Data = srcMessage.Data
- dstMessage.UncompressedSize = srcMessage.UncompressedSize
- dstMessage.MessageGroupID = srcMessage.MessageGroupId
- if len(srcMessage.MetadataItems) > 0 {
- dstMessage.MetadataItems = make([]rawtopiccommon.MetadataItem, 0, len(srcMessage.MetadataItems))
- for _, protoItem := range srcMessage.MetadataItems {
+ dstMessage.Offset.FromInt64(srcMessage.GetOffset())
+ dstMessage.SeqNo = srcMessage.GetSeqNo()
+ dstMessage.CreatedAt = srcMessage.GetCreatedAt().AsTime()
+ dstMessage.Data = srcMessage.GetData()
+ dstMessage.UncompressedSize = srcMessage.GetUncompressedSize()
+ dstMessage.MessageGroupID = srcMessage.GetMessageGroupId()
+ if len(srcMessage.GetMetadataItems()) > 0 {
+ dstMessage.MetadataItems = make([]rawtopiccommon.MetadataItem, 0, len(srcMessage.GetMetadataItems()))
+ for _, protoItem := range srcMessage.GetMetadataItems() {
dstMessage.MetadataItems = append(dstMessage.MetadataItems, rawtopiccommon.MetadataItem{
- Key: protoItem.Key,
- Value: protoItem.Value[:len(protoItem.Value):len(protoItem.Value)],
+ Key: protoItem.GetKey(),
+ Value: protoItem.GetValue()[:len(protoItem.GetValue()):len(protoItem.GetValue())],
})
}
}
}
}
}
+
return nil
}
@@ -314,6 +319,7 @@ func (r *CommitOffsetRequest) toProto() *Ydb_Topic.StreamReadMessage_CommitOffse
dstCommitOffset.Offsets[offsetIndex] = srcPartitionCommitOffset.Offsets[offsetIndex].ToProto()
}
}
+
return res
}
@@ -332,8 +338,9 @@ func (r *OffsetRange) FromProto(p *Ydb_Topic.OffsetsRange) error {
return xerrors.WithStackTrace(errUnexpectedProtobufInOffsets)
}
- r.Start.FromInt64(p.Start)
- r.End.FromInt64(p.End)
+ r.Start.FromInt64(p.GetStart())
+ r.End.FromInt64(p.GetEnd())
+
return nil
}
@@ -353,16 +360,16 @@ type CommitOffsetResponse struct {
}
func (r *CommitOffsetResponse) fromProto(proto *Ydb_Topic.StreamReadMessage_CommitOffsetResponse) error {
- r.PartitionsCommittedOffsets = make([]PartitionCommittedOffset, len(proto.PartitionsCommittedOffsets))
+ r.PartitionsCommittedOffsets = make([]PartitionCommittedOffset, len(proto.GetPartitionsCommittedOffsets()))
for i := range r.PartitionsCommittedOffsets {
- srcCommitted := proto.PartitionsCommittedOffsets[i]
+ srcCommitted := proto.GetPartitionsCommittedOffsets()[i]
if srcCommitted == nil {
return xerrors.WithStackTrace(errors.New("unexpected nil while parse commit offset response"))
}
dstCommitted := &r.PartitionsCommittedOffsets[i]
- dstCommitted.PartitionSessionID.FromInt64(srcCommitted.PartitionSessionId)
- dstCommitted.CommittedOffset.FromInt64(srcCommitted.CommittedOffset)
+ dstCommitted.PartitionSessionID.FromInt64(srcCommitted.GetPartitionSessionId())
+ dstCommitted.CommittedOffset.FromInt64(srcCommitted.GetCommittedOffset())
}
return nil
@@ -407,6 +414,7 @@ func (r *PartitionSessionStatusResponse) fromProto(
return err
}
r.WriteTimeHighWatermark = p.GetWriteTimeHighWatermark().AsTime()
+
return nil
}
@@ -429,16 +437,16 @@ func (r *StartPartitionSessionRequest) fromProto(p *Ydb_Topic.StreamReadMessage_
return xerrors.WithStackTrace(errUnexpectedProtoNilStartPartitionSessionRequest)
}
- if p.PartitionSession == nil {
+ if p.GetPartitionSession() == nil {
return xerrors.WithStackTrace(errUnexpectedNilPartitionSession)
}
- r.PartitionSession.PartitionID = p.PartitionSession.PartitionId
- r.PartitionSession.Path = p.PartitionSession.Path
- r.PartitionSession.PartitionSessionID.FromInt64(p.PartitionSession.PartitionSessionId)
+ r.PartitionSession.PartitionID = p.GetPartitionSession().GetPartitionId()
+ r.PartitionSession.Path = p.GetPartitionSession().GetPath()
+ r.PartitionSession.PartitionSessionID.FromInt64(p.GetPartitionSession().GetPartitionSessionId())
- r.CommittedOffset.FromInt64(p.CommittedOffset)
+ r.CommittedOffset.FromInt64(p.GetCommittedOffset())
- return r.PartitionOffsets.FromProto(p.PartitionOffsets)
+ return r.PartitionOffsets.FromProto(p.GetPartitionOffsets())
}
type PartitionSession struct {
@@ -461,6 +469,7 @@ func (r *StartPartitionSessionResponse) toProto() *Ydb_Topic.StreamReadMessage_S
ReadOffset: r.ReadOffset.ToInt64Pointer(),
CommitOffset: r.CommitOffset.ToInt64Pointer(),
}
+
return res
}
@@ -482,9 +491,10 @@ func (r *StopPartitionSessionRequest) fromProto(proto *Ydb_Topic.StreamReadMessa
if proto == nil {
return xerrors.WithStackTrace(errUnexpectedGrpcNilStopPartitionSessionRequest)
}
- r.PartitionSessionID.FromInt64(proto.PartitionSessionId)
- r.Graceful = proto.Graceful
- r.CommittedOffset.FromInt64(proto.CommittedOffset)
+ r.PartitionSessionID.FromInt64(proto.GetPartitionSessionId())
+ r.Graceful = proto.GetGraceful()
+ r.CommittedOffset.FromInt64(proto.GetCommittedOffset())
+
return nil
}
diff --git a/internal/grpcwrapper/rawtopic/rawtopicreader/rawtopicreader.go b/internal/grpcwrapper/rawtopic/rawtopicreader/rawtopicreader.go
index 12124f1de..17ccc026e 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicreader/rawtopicreader.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicreader/rawtopicreader.go
@@ -3,6 +3,7 @@ package rawtopicreader
import (
"errors"
"fmt"
+ "io"
"reflect"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Topic"
@@ -30,8 +31,14 @@ func (s StreamReader) CloseSend() error {
func (s StreamReader) Recv() (ServerMessage, error) {
grpcMess, err := s.Stream.Recv()
+ if xerrors.Is(err, io.EOF) {
+ return nil, err
+ }
if err != nil {
- err = xerrors.Transport(err)
+ if !xerrors.IsErrorFromServer(err) {
+ err = xerrors.Transport(err)
+ }
+
return nil, err
}
@@ -43,11 +50,12 @@ func (s StreamReader) Recv() (ServerMessage, error) {
return nil, xerrors.WithStackTrace(fmt.Errorf("ydb: bad status from topic server: %v", meta.Status))
}
- switch m := grpcMess.ServerMessage.(type) {
+ switch m := grpcMess.GetServerMessage().(type) {
case *Ydb_Topic.StreamReadMessage_FromServer_InitResponse:
resp := &InitResponse{}
resp.ServerMessageMetadata = meta
resp.fromProto(m.InitResponse)
+
return resp, nil
case *Ydb_Topic.StreamReadMessage_FromServer_ReadResponse:
resp := &ReadResponse{}
@@ -55,6 +63,7 @@ func (s StreamReader) Recv() (ServerMessage, error) {
if err = resp.fromProto(m.ReadResponse); err != nil {
return nil, err
}
+
return resp, nil
case *Ydb_Topic.StreamReadMessage_FromServer_StartPartitionSessionRequest:
resp := &StartPartitionSessionRequest{}
@@ -62,6 +71,7 @@ func (s StreamReader) Recv() (ServerMessage, error) {
if err = resp.fromProto(m.StartPartitionSessionRequest); err != nil {
return nil, err
}
+
return resp, nil
case *Ydb_Topic.StreamReadMessage_FromServer_StopPartitionSessionRequest:
req := &StopPartitionSessionRequest{}
@@ -69,6 +79,7 @@ func (s StreamReader) Recv() (ServerMessage, error) {
if err = req.fromProto(m.StopPartitionSessionRequest); err != nil {
return nil, err
}
+
return req, nil
case *Ydb_Topic.StreamReadMessage_FromServer_CommitOffsetResponse:
resp := &CommitOffsetResponse{}
@@ -76,6 +87,7 @@ func (s StreamReader) Recv() (ServerMessage, error) {
if err = resp.fromProto(m.CommitOffsetResponse); err != nil {
return nil, err
}
+
return resp, nil
case *Ydb_Topic.StreamReadMessage_FromServer_PartitionSessionStatusResponse:
resp := &PartitionSessionStatusResponse{}
@@ -83,16 +95,18 @@ func (s StreamReader) Recv() (ServerMessage, error) {
if err = resp.fromProto(m.PartitionSessionStatusResponse); err != nil {
return nil, err
}
+
return resp, nil
case *Ydb_Topic.StreamReadMessage_FromServer_UpdateTokenResponse:
resp := &UpdateTokenResponse{}
resp.ServerMessageMetadata = meta
resp.MustFromProto(m.UpdateTokenResponse)
+
return resp, nil
default:
return nil, xerrors.WithStackTrace(fmt.Errorf(
"ydb: receive unexpected message (%v): %w",
- reflect.TypeOf(grpcMess.ServerMessage),
+ reflect.TypeOf(grpcMess.GetServerMessage()),
ErrUnexpectedMessageType,
))
}
@@ -107,11 +121,13 @@ func (s StreamReader) Send(msg ClientMessage) (err error) {
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
ClientMessage: &Ydb_Topic.StreamReadMessage_FromClient_InitRequest{InitRequest: m.toProto()},
}
+
return s.Stream.Send(grpcMess)
case *ReadRequest:
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
ClientMessage: &Ydb_Topic.StreamReadMessage_FromClient_ReadRequest{ReadRequest: m.toProto()},
}
+
return s.Stream.Send(grpcMess)
case *StartPartitionSessionResponse:
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
@@ -119,6 +135,7 @@ func (s StreamReader) Send(msg ClientMessage) (err error) {
StartPartitionSessionResponse: m.toProto(),
},
}
+
return s.Stream.Send(grpcMess)
case *StopPartitionSessionResponse:
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
@@ -126,6 +143,7 @@ func (s StreamReader) Send(msg ClientMessage) (err error) {
StopPartitionSessionResponse: m.toProto(),
},
}
+
return s.Stream.Send(grpcMess)
case *CommitOffsetRequest:
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
@@ -133,6 +151,7 @@ func (s StreamReader) Send(msg ClientMessage) (err error) {
CommitOffsetRequest: m.toProto(),
},
}
+
return s.Stream.Send(grpcMess)
case *PartitionSessionStatusRequest:
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
@@ -140,6 +159,7 @@ func (s StreamReader) Send(msg ClientMessage) (err error) {
PartitionSessionStatusRequest: m.toProto(),
},
}
+
return s.Stream.Send(grpcMess)
case *UpdateTokenRequest:
grpcMess := &Ydb_Topic.StreamReadMessage_FromClient{
@@ -147,6 +167,7 @@ func (s StreamReader) Send(msg ClientMessage) (err error) {
UpdateTokenRequest: m.ToProto(),
},
}
+
return s.Stream.Send(grpcMess)
default:
return xerrors.WithStackTrace(fmt.Errorf("ydb: send unexpected message type: %v", reflect.TypeOf(msg)))
diff --git a/internal/grpcwrapper/rawtopic/rawtopicwriter/messages.go b/internal/grpcwrapper/rawtopic/rawtopicwriter/messages.go
index c943506fa..252b4b3cb 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicwriter/messages.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicwriter/messages.go
@@ -133,10 +133,10 @@ type InitResult struct {
}
func (r *InitResult) mustFromProto(response *Ydb_Topic.StreamWriteMessage_InitResponse) {
- r.SessionID = response.SessionId
- r.PartitionID = response.PartitionId
- r.LastSeqNo = response.LastSeqNo
- r.SupportedCodecs.MustFromProto(response.SupportedCodecs)
+ r.SessionID = response.GetSessionId()
+ r.PartitionID = response.GetPartitionId()
+ r.LastSeqNo = response.GetLastSeqNo()
+ r.SupportedCodecs.MustFromProto(response.GetSupportedCodecs())
}
type WriteRequest struct {
@@ -188,7 +188,7 @@ func (d *MessageData) ToProto() (*Ydb_Topic.StreamWriteMessage_WriteRequest_Mess
}
for i := range d.MetadataItems {
- res.MetadataItems = append(res.MetadataItems, &Ydb_Topic.MetadataItem{
+ res.MetadataItems = append(res.GetMetadataItems(), &Ydb_Topic.MetadataItem{
Key: d.MetadataItems[i].Key,
Value: d.MetadataItems[i].Value,
})
@@ -210,14 +210,15 @@ func (r *WriteResult) fromProto(response *Ydb_Topic.StreamWriteMessage_WriteResp
if response == nil {
return xerrors.WithStackTrace(errWriteResultProtoIsNil)
}
- r.Acks = make([]WriteAck, len(response.Acks))
- for i := range response.Acks {
- if err := r.Acks[i].fromProto(response.Acks[i]); err != nil {
+ r.Acks = make([]WriteAck, len(response.GetAcks()))
+ for i := range response.GetAcks() {
+ if err := r.Acks[i].fromProto(response.GetAcks()[i]); err != nil {
return err
}
}
- r.PartitionID = response.PartitionId
- return r.WriteStatistics.fromProto(response.WriteStatistics)
+ r.PartitionID = response.GetPartitionId()
+
+ return r.WriteStatistics.fromProto(response.GetWriteStatistics())
}
type WriteAck struct {
@@ -229,8 +230,9 @@ func (wa *WriteAck) fromProto(pb *Ydb_Topic.StreamWriteMessage_WriteResponse_Wri
if pb == nil {
return xerrors.WithStackTrace(errWriteResultResponseWriteAckIsNil)
}
- wa.SeqNo = pb.SeqNo
- return wa.MessageWriteStatus.fromProto(pb.MessageWriteStatus)
+ wa.SeqNo = pb.GetSeqNo()
+
+ return wa.MessageWriteStatus.fromProto(pb.GetMessageWriteStatus())
}
// MessageWriteStatus is struct because it included in per-message structure and
@@ -246,11 +248,13 @@ func (s *MessageWriteStatus) fromProto(status interface{}) error {
switch v := status.(type) {
case *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Written_:
s.Type = WriteStatusTypeWritten
- s.WrittenOffset = v.Written.Offset
+ s.WrittenOffset = v.Written.GetOffset()
+
return nil
case *Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Skipped_:
s.Type = WriteStatusTypeSkipped
- s.SkippedReason = WriteStatusSkipReason(v.Skipped.Reason)
+ s.SkippedReason = WriteStatusSkipReason(v.Skipped.GetReason())
+
return nil
default:
return xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf("ydb: unexpected write status type: %v", reflect.TypeOf(v))))
@@ -284,10 +288,11 @@ func (s *WriteStatistics) fromProto(statistics *Ydb_Topic.StreamWriteMessage_Wri
return xerrors.WithStackTrace(errWriteResultResponseStatisticIsNil)
}
- s.PersistingTime = statistics.PersistingTime.AsDuration()
- s.MinQueueWaitTime = statistics.MinQueueWaitTime.AsDuration()
- s.MaxQueueWaitTime = statistics.MaxQueueWaitTime.AsDuration()
- s.TopicQuotaWaitTime = statistics.TopicQuotaWaitTime.AsDuration()
+ s.PersistingTime = statistics.GetPersistingTime().AsDuration()
+ s.MinQueueWaitTime = statistics.GetMinQueueWaitTime().AsDuration()
+ s.MaxQueueWaitTime = statistics.GetMaxQueueWaitTime().AsDuration()
+ s.TopicQuotaWaitTime = statistics.GetTopicQuotaWaitTime().AsDuration()
+
return nil
}
@@ -298,9 +303,9 @@ type UpdateTokenRequest struct {
}
type UpdateTokenResponse struct {
+ rawtopiccommon.UpdateTokenResponse
+
serverMessageImpl
rawtopiccommon.ServerMessageMetadata
-
- rawtopiccommon.UpdateTokenResponse
}
diff --git a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go
index 3b62de655..e2689df5a 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go
@@ -41,7 +41,10 @@ func (w *StreamWriter) Recv() (ServerMessage, error) {
grpcMsg, err := w.Stream.Recv()
if err != nil {
- err = xerrors.Transport(err)
+ if !xerrors.IsErrorFromServer(err) {
+ err = xerrors.Transport(err)
+ }
+
return nil, xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf(
"ydb: failed to read grpc message from writer stream: %w",
err,
@@ -56,11 +59,12 @@ func (w *StreamWriter) Recv() (ServerMessage, error) {
return nil, xerrors.WithStackTrace(fmt.Errorf("ydb: bad status from topic server: %v", meta.Status))
}
- switch v := grpcMsg.ServerMessage.(type) {
+ switch v := grpcMsg.GetServerMessage().(type) {
case *Ydb_Topic.StreamWriteMessage_FromServer_InitResponse:
var res InitResult
res.ServerMessageMetadata = meta
res.mustFromProto(v.InitResponse)
+
return &res, nil
case *Ydb_Topic.StreamWriteMessage_FromServer_WriteResponse:
var res WriteResult
@@ -69,10 +73,12 @@ func (w *StreamWriter) Recv() (ServerMessage, error) {
if err != nil {
return nil, err
}
+
return &res, nil
case *Ydb_Topic.StreamWriteMessage_FromServer_UpdateTokenResponse:
var res UpdateTokenResponse
res.MustFromProto(v.UpdateTokenResponse)
+
return &res, nil
default:
return nil, xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf(
@@ -104,6 +110,7 @@ func (w *StreamWriter) Send(rawMsg ClientMessage) (err error) {
if writeErr != nil {
return writeErr
}
+
return sendWriteRequest(w.Stream.Send, writeReqProto)
case *UpdateTokenRequest:
protoMsg.ClientMessage = &Ydb_Topic.StreamWriteMessage_FromClient_UpdateTokenRequest{
@@ -120,6 +127,7 @@ func (w *StreamWriter) Send(rawMsg ClientMessage) (err error) {
if err != nil {
return xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf("ydb: failed to send grpc message to writer stream: %w", err)))
}
+
return nil
}
@@ -164,7 +172,7 @@ func sendWriteRequest(send sendFunc, req *Ydb_Topic.StreamWriteMessage_FromClien
return sendErr
}
- grpcMessages := req.WriteRequest.Messages
+ grpcMessages := req.WriteRequest.GetMessages()
if grpcStatus.Code() != codes.ResourceExhausted || len(grpcMessages) < 2 {
return sendErr
}
@@ -182,5 +190,6 @@ func sendWriteRequest(send sendFunc, req *Ydb_Topic.StreamWriteMessage_FromClien
}
req.WriteRequest.Messages = lastMessages
+
return sendWriteRequest(send, req)
}
diff --git a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go
index 4233529d7..f076adab9 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go
@@ -25,7 +25,8 @@ func TestSendWriteRequest(t *testing.T) {
sendCounter := 0
var send sendFunc = func(req *Ydb_Topic.StreamWriteMessage_FromClient) error {
sendCounter++
- require.Equal(t, expected, req.ClientMessage)
+ require.Equal(t, expected, req.GetClientMessage())
+
return nil
}
err := sendWriteRequest(send, expected)
@@ -71,7 +72,7 @@ func TestSendWriteRequest(t *testing.T) {
}
getWriteRequest := func(req *Ydb_Topic.StreamWriteMessage_FromClient) *Ydb_Topic.StreamWriteMessage_WriteRequest {
- return req.ClientMessage.(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest).WriteRequest
+ return req.GetClientMessage().(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest).WriteRequest
}
sendCounter := 0
@@ -81,6 +82,7 @@ func TestSendWriteRequest(t *testing.T) {
switch sendCounter {
case 1:
require.Equal(t, originalMessage, req)
+
return grpcStatus.Error(codes.ResourceExhausted, "test resource exhausted")
case 2:
require.Equal(t, split1, req)
@@ -89,6 +91,7 @@ func TestSendWriteRequest(t *testing.T) {
default:
t.Fatal()
}
+
return nil
}
diff --git a/internal/grpcwrapper/rawydb/issues.go b/internal/grpcwrapper/rawydb/issues.go
index 2c04ce799..09ed1b3e3 100644
--- a/internal/grpcwrapper/rawydb/issues.go
+++ b/internal/grpcwrapper/rawydb/issues.go
@@ -17,9 +17,10 @@ func (issuesPointer *Issues) FromProto(p []*Ydb_Issue.IssueMessage) error {
issues := *issuesPointer
for i := range issues {
if err := issues[i].FromProto(p[i]); err != nil {
- return nil
+ return err
}
}
+
return nil
}
@@ -29,6 +30,7 @@ func (issuesPointer *Issues) String() string {
for i := range issues {
issuesStrings[i] = issues[i].String()
}
+
return strings.Join(issuesStrings, ", ")
}
diff --git a/internal/grpcwrapper/rawydb/operation.go b/internal/grpcwrapper/rawydb/operation.go
index 3c6dcafca..5073cb8aa 100644
--- a/internal/grpcwrapper/rawydb/operation.go
+++ b/internal/grpcwrapper/rawydb/operation.go
@@ -21,13 +21,15 @@ func (o *Operation) FromProto(proto *Ydb_Operations.Operation) error {
if err := o.Status.FromProto(proto.GetStatus()); err != nil {
return err
}
- return o.Issues.FromProto(proto.Issues)
+
+ return o.Issues.FromProto(proto.GetIssues())
}
func (o *Operation) OperationStatusToError() error {
if !o.Status.IsSuccess() {
return xerrors.WithStackTrace(fmt.Errorf("ydb: create topic error [%v]: %v", o.Status, o.Issues))
}
+
return nil
}
@@ -35,5 +37,6 @@ func (o *Operation) FromProtoWithStatusCheck(proto *Ydb_Operations.Operation) er
if err := o.FromProto(proto); err != nil {
return err
}
+
return o.OperationStatusToError()
}
diff --git a/internal/grpcwrapper/rawydb/operation_params.go b/internal/grpcwrapper/rawydb/operation_params.go
index b2fc9aeba..21d80eba1 100644
--- a/internal/grpcwrapper/rawydb/operation_params.go
+++ b/internal/grpcwrapper/rawydb/operation_params.go
@@ -19,6 +19,7 @@ func (p *OperationParams) ToProto() *Ydb_Operations.OperationParams {
}
res.OperationTimeout = p.OperationTimeout.ToProto()
res.CancelAfter = p.CancelAfter.ToProto()
+
return res
}
diff --git a/internal/grpcwrapper/rawydb/status.go b/internal/grpcwrapper/rawydb/status.go
index f31482ac7..e6263b27c 100644
--- a/internal/grpcwrapper/rawydb/status.go
+++ b/internal/grpcwrapper/rawydb/status.go
@@ -11,6 +11,7 @@ const (
func (s *StatusCode) FromProto(p Ydb.StatusIds_StatusCode) error {
*s = StatusCode(p)
+
return nil
}
diff --git a/internal/meta/context.go b/internal/meta/context.go
index 2df7010c8..b3a410dcc 100644
--- a/internal/meta/context.go
+++ b/internal/meta/context.go
@@ -11,6 +11,7 @@ func WithTraceID(ctx context.Context, traceID string) context.Context {
if md, has := metadata.FromOutgoingContext(ctx); !has || len(md[HeaderTraceID]) == 0 {
return metadata.AppendToOutgoingContext(ctx, HeaderTraceID, traceID)
}
+
return ctx
}
@@ -18,12 +19,19 @@ func traceID(ctx context.Context) (string, bool) {
if md, has := metadata.FromOutgoingContext(ctx); has && len(md[HeaderTraceID]) > 0 {
return md[HeaderTraceID][0], true
}
+
return "", false
}
-// WithUserAgent returns a copy of parent context with custom user-agent info
-func WithUserAgent(ctx context.Context, userAgent string) context.Context {
- return metadata.AppendToOutgoingContext(ctx, HeaderUserAgent, userAgent)
+// WithApplicationName returns a copy of parent context with custom user-agent info
+func WithApplicationName(ctx context.Context, applicationName string) context.Context {
+ md, has := metadata.FromOutgoingContext(ctx)
+ if !has {
+ md = metadata.MD{}
+ }
+ md.Set(HeaderApplicationName, applicationName)
+
+ return metadata.NewOutgoingContext(ctx, md)
}
// WithRequestType returns a copy of parent context with custom request type
@@ -32,10 +40,11 @@ func WithRequestType(ctx context.Context, requestType string) context.Context {
}
// WithAllowFeatures returns a copy of parent context with allowed client feature
-func WithAllowFeatures(ctx context.Context, features []string) context.Context {
+func WithAllowFeatures(ctx context.Context, features ...string) context.Context {
kv := make([]string, 0, len(features)*2)
for _, feature := range features {
kv = append(kv, HeaderClientCapabilities, feature)
}
+
return metadata.AppendToOutgoingContext(ctx, kv...)
}
diff --git a/internal/meta/context_test.go b/internal/meta/context_test.go
new file mode 100644
index 000000000..1bfdabcc5
--- /dev/null
+++ b/internal/meta/context_test.go
@@ -0,0 +1,61 @@
+package meta
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "google.golang.org/grpc/metadata"
+)
+
+func TestContext(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ ctx context.Context
+ header string
+ values []string
+ }{
+ {
+ name: "WithApplicationName",
+ ctx: WithApplicationName(context.Background(), "test"),
+ header: HeaderApplicationName,
+ values: []string{"test"},
+ },
+ {
+ name: "WithApplicationName",
+ ctx: WithApplicationName(
+ WithApplicationName(
+ context.Background(),
+ "test1",
+ ),
+ "test2",
+ ),
+ header: HeaderApplicationName,
+ values: []string{"test2"},
+ },
+ {
+ name: "WithTraceID",
+ ctx: WithTraceID(context.Background(), "my-trace-id"),
+ header: HeaderTraceID,
+ values: []string{"my-trace-id"},
+ },
+ {
+ name: "WithRequestType",
+ ctx: WithRequestType(context.Background(), "my-request-type"),
+ header: HeaderRequestType,
+ values: []string{"my-request-type"},
+ },
+ {
+ name: "WithAllowFeatures",
+ ctx: WithAllowFeatures(context.Background(), "feature-1", "feature-2", "feature-3"),
+ header: HeaderClientCapabilities,
+ values: []string{"feature-1", "feature-2", "feature-3"},
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ md, has := metadata.FromOutgoingContext(tt.ctx)
+ require.True(t, has)
+ require.Equal(t, tt.values, md.Get(tt.header))
+ })
+ }
+}
diff --git a/internal/meta/headers.go b/internal/meta/headers.go
index e68ca4ad4..41f025941 100644
--- a/internal/meta/headers.go
+++ b/internal/meta/headers.go
@@ -7,8 +7,9 @@ const (
HeaderVersion = "x-ydb-sdk-build-info"
HeaderRequestType = "x-ydb-request-type"
HeaderTraceID = "x-ydb-trace-id"
- HeaderUserAgent = "x-ydb-user-agent"
+ HeaderApplicationName = "x-ydb-application-name"
HeaderClientCapabilities = "x-ydb-client-capabilities"
+ HeaderClientPid = "x-ydb-client-pid"
// outgoing hints
HintSessionBalancer = "session-balancer"
diff --git a/internal/meta/incoming.go b/internal/meta/incoming.go
index c4e95e384..940547d2a 100644
--- a/internal/meta/incoming.go
+++ b/internal/meta/incoming.go
@@ -20,6 +20,7 @@ func WithTrailerCallback(ctx context.Context, callback MetadataCallback) context
},
))
}
+
return context.WithValue(ctx, metadataCallbackKey{}, callback)
}
diff --git a/internal/meta/meta.go b/internal/meta/meta.go
index fbe4f4603..8f856379d 100644
--- a/internal/meta/meta.go
+++ b/internal/meta/meta.go
@@ -3,6 +3,8 @@ package meta
import (
"context"
"fmt"
+ "os"
+ "strconv"
"google.golang.org/grpc/metadata"
@@ -13,6 +15,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
+var pid = os.Getpid()
+
func New(
database string,
credentials credentials.Credentials,
@@ -20,23 +24,25 @@ func New(
opts ...Option,
) *Meta {
m := &Meta{
+ pid: strconv.Itoa(pid),
trace: trace,
credentials: credentials,
database: database,
}
- for _, o := range opts {
- if o != nil {
- o(m)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(m)
}
}
+
return m
}
type Option func(m *Meta)
-func WithUserAgentOption(userAgent string) Option {
+func WithApplicationNameOption(applicationName string) Option {
return func(m *Meta) {
- m.userAgents = append(m.userAgents, userAgent)
+ m.applicationName = applicationName
}
}
@@ -66,12 +72,13 @@ func ForbidOption(feature string) Option {
}
type Meta struct {
- trace *trace.Driver
- credentials credentials.Credentials
- database string
- requestsType string
- userAgents []string
- capabilities []string
+ pid string
+ trace *trace.Driver
+ credentials credentials.Credentials
+ database string
+ requestsType string
+ applicationName string
+ capabilities []string
}
func (m *Meta) meta(ctx context.Context) (_ metadata.MD, err error) {
@@ -80,6 +87,8 @@ func (m *Meta) meta(ctx context.Context) (_ metadata.MD, err error) {
md = metadata.MD{}
}
+ md.Set(HeaderClientPid, m.pid)
+
if len(md.Get(HeaderDatabase)) == 0 {
md.Set(HeaderDatabase, m.database)
}
@@ -94,8 +103,8 @@ func (m *Meta) meta(ctx context.Context) (_ metadata.MD, err error) {
}
}
- if len(m.userAgents) != 0 {
- md.Append(HeaderUserAgent, m.userAgents...)
+ if m.applicationName != "" {
+ md.Append(HeaderApplicationName, m.applicationName)
}
if len(m.capabilities) > 0 {
@@ -108,7 +117,9 @@ func (m *Meta) meta(ctx context.Context) (_ metadata.MD, err error) {
var token string
- done := trace.DriverOnGetCredentials(m.trace, &ctx, stack.FunctionID(""))
+ done := trace.DriverOnGetCredentials(m.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/meta.(*Meta).meta"),
+ )
defer func() {
done(token, err)
}()
@@ -118,6 +129,7 @@ func (m *Meta) meta(ctx context.Context) (_ metadata.MD, err error) {
if stringer, ok := m.credentials.(fmt.Stringer); ok {
return nil, xerrors.WithStackTrace(fmt.Errorf("%w: %s", err, stringer.String()))
}
+
return nil, xerrors.WithStackTrace(err)
}
@@ -131,5 +143,6 @@ func (m *Meta) Context(ctx context.Context) (_ context.Context, err error) {
if err != nil {
return ctx, xerrors.WithStackTrace(err)
}
+
return metadata.NewOutgoingContext(ctx, md), nil
}
diff --git a/internal/meta/test/meta_test.go b/internal/meta/test/meta_test.go
index e077b7f6b..139187ef6 100644
--- a/internal/meta/test/meta_test.go
+++ b/internal/meta/test/meta_test.go
@@ -20,13 +20,11 @@ func TestMetaRequiredHeaders(t *testing.T) {
credentials.NewAccessTokenCredentials("token"),
&trace.Driver{},
internal.WithRequestTypeOption("requestType"),
- internal.WithUserAgentOption("user-agent"),
+ internal.WithApplicationNameOption("test app"),
)
ctx := context.Background()
- ctx = meta.WithUserAgent(ctx, "userAgent")
-
ctx = meta.WithTraceID(ctx, "traceID")
ctx = metadata.AppendToOutgoingContext(ctx, "some-user-header", "some-user-value")
@@ -43,7 +41,9 @@ func TestMetaRequiredHeaders(t *testing.T) {
require.Equal(t, []string{"database"}, md.Get(internal.HeaderDatabase))
require.Equal(t, []string{"requestType"}, md.Get(internal.HeaderRequestType))
require.Equal(t, []string{"token"}, md.Get(internal.HeaderTicket))
- require.Equal(t, []string{"userAgent", "user-agent"}, md.Get(internal.HeaderUserAgent))
+ require.NotEmpty(t, md.Get(internal.HeaderClientPid))
+ require.NotEmpty(t, md.Get(internal.HeaderClientPid)[0])
+ require.Equal(t, []string{"test app"}, md.Get(internal.HeaderApplicationName))
require.Equal(t, []string{"traceID"}, md.Get(internal.HeaderTraceID))
require.Equal(t, []string{
"ydb-go-sdk/" + version.Major + "." + version.Minor + "." + version.Patch,
diff --git a/internal/meta/trace_id.go b/internal/meta/trace_id.go
index e93792c35..182c57dac 100644
--- a/internal/meta/trace_id.go
+++ b/internal/meta/trace_id.go
@@ -19,12 +19,15 @@ func TraceID(ctx context.Context, opts ...func(opts *newTraceIDOpts)) (context.C
}
options := newTraceIDOpts{newRandom: uuid.NewRandom}
for _, opt := range opts {
- opt(&options)
+ if opt != nil {
+ opt(&options)
+ }
}
uuid, err := options.newRandom()
if err != nil {
return ctx, "", xerrors.WithStackTrace(err)
}
id := uuid.String()
+
return metadata.AppendToOutgoingContext(ctx, HeaderTraceID, id), id, nil
}
diff --git a/internal/mock/conn.go b/internal/mock/conn.go
index 1b9a66523..ac57f6c41 100644
--- a/internal/mock/conn.go
+++ b/internal/mock/conn.go
@@ -67,11 +67,13 @@ func (c *Conn) GetState() conn.State {
func (c *Conn) SetState(ctx context.Context, state conn.State) conn.State {
c.State = state
+
return c.State
}
func (c *Conn) Unban(ctx context.Context) conn.State {
c.SetState(ctx, conn.Online)
+
return conn.Online
}
@@ -115,6 +117,7 @@ func (e *Endpoint) String() string {
func (e *Endpoint) Copy() endpoint.Endpoint {
c := *e
+
return &c
}
diff --git a/internal/operation/context.go b/internal/operation/context.go
index b82d505b4..3ce2e1ee5 100644
--- a/internal/operation/context.go
+++ b/internal/operation/context.go
@@ -17,6 +17,7 @@ func WithTimeout(ctx context.Context, operationTimeout time.Duration) context.Co
// The current cancelation timeout is already smaller than the new one.
return ctx
}
+
return context.WithValue(ctx, ctxOperationTimeoutKey{}, operationTimeout)
}
@@ -28,6 +29,7 @@ func WithCancelAfter(ctx context.Context, operationCancelAfter time.Duration) co
// The current cancelation timeout is already smaller than the new one.
return ctx
}
+
return context.WithValue(ctx, ctxOperationCancelAfterKey{}, operationCancelAfter)
}
@@ -35,6 +37,7 @@ func WithCancelAfter(ctx context.Context, operationCancelAfter time.Duration) co
// YDB should try to cancel operation and return result regardless of the cancelation.
func Timeout(ctx context.Context) (d time.Duration, ok bool) {
d, ok = ctx.Value(ctxOperationTimeoutKey{}).(time.Duration)
+
return
}
@@ -42,6 +45,7 @@ func Timeout(ctx context.Context) (d time.Duration, ok bool) {
// YDB should try to cancel operation and return result regardless of the cancellation.
func CancelAfter(ctx context.Context) (d time.Duration, ok bool) {
d, ok = ctx.Value(ctxOperationCancelAfterKey{}).(time.Duration)
+
return
}
@@ -50,5 +54,6 @@ func untilDeadline(ctx context.Context) (time.Duration, bool) {
if ok {
return time.Until(deadline), true
}
+
return 0, false
}
diff --git a/internal/operation/params.go b/internal/operation/params.go
index 2ca1c3c01..f45e941f8 100644
--- a/internal/operation/params.go
+++ b/internal/operation/params.go
@@ -25,6 +25,7 @@ func Params(
if timeout == 0 && cancelAfter == 0 && mode == 0 {
return nil
}
+
return &Ydb_Operations.OperationParams{
OperationMode: mode.toYDB(),
OperationTimeout: timeoutParam(timeout),
diff --git a/internal/operation/params_test.go b/internal/operation/params_test.go
index 256dd1cb9..605453279 100644
--- a/internal/operation/params_test.go
+++ b/internal/operation/params_test.go
@@ -224,6 +224,7 @@ func TestParams(t *testing.T) {
),
time.Second*5,
), time.Second*10)
+
return ctx
}(),
timeout: time.Second * 2,
@@ -244,6 +245,7 @@ func TestParams(t *testing.T) {
),
time.Second*5,
), time.Second*1)
+
return ctx
}(),
timeout: time.Second * 2,
@@ -264,6 +266,7 @@ func TestParams(t *testing.T) {
),
time.Second*5,
), time.Second*1)
+
return ctx
}(),
preferContextTimeout: true,
@@ -279,6 +282,7 @@ func TestParams(t *testing.T) {
{
ctx: func() context.Context {
ctx, _ := xcontext.WithTimeout(context.Background(), time.Second*1)
+
return ctx
}(),
preferContextTimeout: true,
@@ -306,27 +310,28 @@ func TestParams(t *testing.T) {
tt.exp,
)
}
+
return
}
- if !reflect.DeepEqual(got.OperationMode, tt.exp.OperationMode) {
+ if !reflect.DeepEqual(got.GetOperationMode(), tt.exp.GetOperationMode()) {
t.Errorf(
"Params().OperationMode: %v, want: %v",
- got.OperationMode,
- tt.exp.OperationMode,
+ got.GetOperationMode(),
+ tt.exp.GetOperationMode(),
)
}
- if !reflect.DeepEqual(got.CancelAfter, tt.exp.CancelAfter) {
+ if !reflect.DeepEqual(got.GetCancelAfter(), tt.exp.GetCancelAfter()) {
t.Errorf(
"Params().CancelAfter: %v, want: %v",
- got.CancelAfter.AsDuration(),
- tt.exp.CancelAfter.AsDuration(),
+ got.GetCancelAfter().AsDuration(),
+ tt.exp.GetCancelAfter().AsDuration(),
)
}
- if got.OperationTimeout.AsDuration() > tt.exp.OperationTimeout.AsDuration() {
+ if got.GetOperationTimeout().AsDuration() > tt.exp.GetOperationTimeout().AsDuration() {
t.Errorf(
"Params().OperationTimeout: %v, want: <= %v",
- got.OperationTimeout.AsDuration(),
- tt.exp.OperationTimeout.AsDuration(),
+ got.GetOperationTimeout().AsDuration(),
+ tt.exp.GetOperationTimeout().AsDuration(),
)
}
})
diff --git a/internal/operation/status.go b/internal/operation/status.go
new file mode 100644
index 000000000..4b57ff53d
--- /dev/null
+++ b/internal/operation/status.go
@@ -0,0 +1,11 @@
+package operation
+
+import (
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Issue"
+)
+
+type Status interface {
+ GetStatus() Ydb.StatusIds_StatusCode
+ GetIssues() []*Ydb_Issue.IssueMessage
+}
diff --git a/internal/operation/timeout.go b/internal/operation/timeout.go
index dc62bdddb..a29dbe76b 100644
--- a/internal/operation/timeout.go
+++ b/internal/operation/timeout.go
@@ -10,5 +10,6 @@ func timeoutParam(d time.Duration) *durationpb.Duration {
if d > 0 {
return durationpb.New(d)
}
+
return nil
}
diff --git a/internal/params/builder.go b/internal/params/builder.go
new file mode 100644
index 000000000..ce8421fb0
--- /dev/null
+++ b/internal/params/builder.go
@@ -0,0 +1,19 @@
+package params
+
+type (
+ Builder struct {
+ params Parameters
+ }
+)
+
+func (b Builder) Build() *Parameters {
+ return &b.params
+}
+
+func (b Builder) Param(name string) *Parameter {
+ return &Parameter{
+ parent: b,
+ name: name,
+ value: nil,
+ }
+}
diff --git a/internal/params/builder_test.go b/internal/params/builder_test.go
new file mode 100644
index 000000000..b1d004cbf
--- /dev/null
+++ b/internal/params/builder_test.go
@@ -0,0 +1,441 @@
+package params
+
+import (
+ "encoding/json"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func paramsToJSON(params map[string]*Ydb.TypedValue) string {
+ b, _ := json.MarshalIndent(params, "", "\t") //nolint:errchkjson
+
+ return string(b)
+}
+
+func TestBuilder(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ args: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int64",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ args: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int32",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ args: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int16",
+ args: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ args: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int8",
+ args: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Bool",
+ args: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ {
+ method: "Text",
+ args: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ args: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ {
+ method: "Float",
+ args: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Double",
+ args: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Interval",
+ args: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ {
+ method: "Date",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ {
+ method: "JSON",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "YSON",
+ args: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ },
+ },
+ },
+ {
+ method: "UUID",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x")
+
+ result, ok := xtest.CallMethod(item, tc.method, tc.args...)[0].(Builder)
+ require.True(t, ok)
+
+ params := result.Build().ToYDB(a)
+
+ require.Equal(t,
+ paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: tc.expected.Type,
+ Value: tc.expected.Value,
+ },
+ }),
+ paramsToJSON(params),
+ )
+ })
+ }
+}
diff --git a/internal/params/dict.go b/internal/params/dict.go
new file mode 100644
index 000000000..d772f659e
--- /dev/null
+++ b/internal/params/dict.go
@@ -0,0 +1,469 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ dict struct {
+ parent Builder
+ name string
+ values []value.DictValueField
+ }
+ dictPair struct {
+ parent *dict
+ keyValue value.Value
+ }
+ dictValue struct {
+ pair *dictPair
+ }
+)
+
+func (d *dict) Add() *dictPair {
+ return &dictPair{
+ parent: d,
+ }
+}
+
+func (d *dict) AddPairs(pairs ...value.DictValueField) *dict {
+ d.values = append(d.values, pairs...)
+
+ return d
+}
+
+func (d *dictPair) Text(v string) *dictValue {
+ d.keyValue = value.TextValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Bytes(v []byte) *dictValue {
+ d.keyValue = value.BytesValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Bool(v bool) *dictValue {
+ d.keyValue = value.BoolValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Uint64(v uint64) *dictValue {
+ d.keyValue = value.Uint64Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Int64(v int64) *dictValue {
+ d.keyValue = value.Int64Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Uint32(v uint32) *dictValue {
+ d.keyValue = value.Uint32Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Int32(v int32) *dictValue {
+ d.keyValue = value.Int32Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Uint16(v uint16) *dictValue {
+ d.keyValue = value.Uint16Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Int16(v int16) *dictValue {
+ d.keyValue = value.Int16Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Uint8(v uint8) *dictValue {
+ d.keyValue = value.Uint8Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Int8(v int8) *dictValue {
+ d.keyValue = value.Int8Value(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Float(v float32) *dictValue {
+ d.keyValue = value.FloatValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Double(v float64) *dictValue {
+ d.keyValue = value.DoubleValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Decimal(v [16]byte, precision, scale uint32) *dictValue {
+ d.keyValue = value.DecimalValue(v, precision, scale)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Timestamp(v time.Time) *dictValue {
+ d.keyValue = value.TimestampValueFromTime(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Date(v time.Time) *dictValue {
+ d.keyValue = value.DateValueFromTime(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Datetime(v time.Time) *dictValue {
+ d.keyValue = value.DatetimeValueFromTime(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) Interval(v time.Duration) *dictValue {
+ d.keyValue = value.IntervalValueFromDuration(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) JSON(v string) *dictValue {
+ d.keyValue = value.JSONValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) JSONDocument(v string) *dictValue {
+ d.keyValue = value.JSONDocumentValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) YSON(v []byte) *dictValue {
+ d.keyValue = value.YSONValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) UUID(v [16]byte) *dictValue {
+ d.keyValue = value.UUIDValue(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) TzDate(v time.Time) *dictValue {
+ d.keyValue = value.TzDateValueFromTime(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) TzTimestamp(v time.Time) *dictValue {
+ d.keyValue = value.TzTimestampValueFromTime(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictPair) TzDatetime(v time.Time) *dictValue {
+ d.keyValue = value.TzDatetimeValueFromTime(v)
+
+ return &dictValue{
+ pair: d,
+ }
+}
+
+func (d *dictValue) Text(v string) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.TextValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Bytes(v []byte) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.BytesValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Bool(v bool) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.BoolValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Uint64(v uint64) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Uint64Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Int64(v int64) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Int64Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Uint32(v uint32) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Uint32Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Int32(v int32) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Int32Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Uint16(v uint16) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Uint16Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Int16(v int16) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Int16Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Uint8(v uint8) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Uint8Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Int8(v int8) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.Int8Value(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Float(v float32) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.FloatValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Double(v float64) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.DoubleValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Decimal(v [16]byte, precision, scale uint32) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.DecimalValue(v, precision, scale),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Timestamp(v time.Time) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.TimestampValueFromTime(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Date(v time.Time) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.DateValueFromTime(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Datetime(v time.Time) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.DatetimeValueFromTime(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) Interval(v time.Duration) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.IntervalValueFromDuration(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) JSON(v string) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.JSONValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) JSONDocument(v string) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.JSONDocumentValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) YSON(v []byte) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.YSONValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) UUID(v [16]byte) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.UUIDValue(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) TzDate(v time.Time) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.TzDateValueFromTime(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) TzTimestamp(v time.Time) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.TzTimestampValueFromTime(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dictValue) TzDatetime(v time.Time) *dict {
+ d.pair.parent.values = append(d.pair.parent.values, value.DictValueField{
+ K: d.pair.keyValue,
+ V: value.TzDatetimeValueFromTime(v),
+ })
+
+ return d.pair.parent
+}
+
+func (d *dict) EndDict() Builder {
+ d.parent.params = append(d.parent.params, &Parameter{
+ parent: d.parent,
+ name: d.name,
+ value: value.DictValue(d.values...),
+ })
+
+ return d.parent
+}
diff --git a/internal/params/dict_test.go b/internal/params/dict_test.go
new file mode 100644
index 000000000..2fed82d33
--- /dev/null
+++ b/internal/params/dict_test.go
@@ -0,0 +1,519 @@
+package params
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestDict(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ args: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int64",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ args: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int32",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ args: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int16",
+ args: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ args: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int8",
+ args: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Bool",
+ args: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ {
+ method: "Text",
+ args: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ args: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ {
+ method: "Float",
+ args: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Double",
+ args: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Interval",
+ args: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ {
+ method: "Date",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ {
+ method: "JSON",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "YSON",
+ args: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ },
+ },
+ },
+ {
+ method: "UUID",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ }
+
+ for _, key := range tests {
+ for _, val := range tests {
+ t.Run(fmt.Sprintf("%s:%s", key.method, val.method), func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginDict().Add()
+
+ addedKey, ok := xtest.CallMethod(item, key.method, key.args...)[0].(*dictValue)
+ require.True(t, ok)
+
+ d, ok := xtest.CallMethod(addedKey, val.method, val.args...)[0].(*dict)
+ require.True(t, ok)
+
+ params := d.EndDict().Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DictType{
+ DictType: &Ydb.DictType{
+ Key: key.expected.Type,
+ Payload: val.expected.Type,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Pairs: []*Ydb.ValuePair{
+ {
+ Key: key.expected.Value,
+ Payload: val.expected.Value,
+ },
+ },
+ },
+ },
+ }), paramsToJSON(params))
+ })
+ }
+ }
+}
+
+func TestDict_AddPairs(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ pairs := []value.DictValueField{
+ {
+ K: value.Int64Value(123),
+ V: value.BoolValue(true),
+ },
+ {
+ K: value.Int64Value(321),
+ V: value.BoolValue(false),
+ },
+ }
+
+ params := Builder{}.Param("$x").BeginDict().AddPairs(pairs...).EndDict().Build().ToYDB(a)
+
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DictType{
+ DictType: &Ydb.DictType{
+ Key: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ Payload: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Pairs: []*Ydb.ValuePair{
+ {
+ Key: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ Payload: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ {
+ Key: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 321,
+ },
+ },
+ Payload: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ },
+ },
+ },
+ },
+ },
+ }), paramsToJSON(params))
+}
diff --git a/internal/params/list.go b/internal/params/list.go
new file mode 100644
index 000000000..b70501e5c
--- /dev/null
+++ b/internal/params/list.go
@@ -0,0 +1,190 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ list struct {
+ parent Builder
+ name string
+ values []value.Value
+ }
+ listItem struct {
+ parent *list
+ }
+)
+
+func (l *list) Add() *listItem {
+ return &listItem{
+ parent: l,
+ }
+}
+
+func (l *list) AddItems(items ...value.Value) *list {
+ l.values = append(l.values, items...)
+
+ return l
+}
+
+func (l *list) EndList() Builder {
+ l.parent.params = append(l.parent.params, &Parameter{
+ parent: l.parent,
+ name: l.name,
+ value: value.ListValue(l.values...),
+ })
+
+ return l.parent
+}
+
+func (l *listItem) Text(v string) *list {
+ l.parent.values = append(l.parent.values, value.TextValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) Bytes(v []byte) *list {
+ l.parent.values = append(l.parent.values, value.BytesValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) Bool(v bool) *list {
+ l.parent.values = append(l.parent.values, value.BoolValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) Uint64(v uint64) *list {
+ l.parent.values = append(l.parent.values, value.Uint64Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Int64(v int64) *list {
+ l.parent.values = append(l.parent.values, value.Int64Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Uint32(v uint32) *list {
+ l.parent.values = append(l.parent.values, value.Uint32Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Int32(v int32) *list {
+ l.parent.values = append(l.parent.values, value.Int32Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Uint16(v uint16) *list {
+ l.parent.values = append(l.parent.values, value.Uint16Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Int16(v int16) *list {
+ l.parent.values = append(l.parent.values, value.Int16Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Uint8(v uint8) *list {
+ l.parent.values = append(l.parent.values, value.Uint8Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Int8(v int8) *list {
+ l.parent.values = append(l.parent.values, value.Int8Value(v))
+
+ return l.parent
+}
+
+func (l *listItem) Float(v float32) *list {
+ l.parent.values = append(l.parent.values, value.FloatValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) Double(v float64) *list {
+ l.parent.values = append(l.parent.values, value.DoubleValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) Decimal(v [16]byte, precision, scale uint32) *list {
+ l.parent.values = append(l.parent.values, value.DecimalValue(v, precision, scale))
+
+ return l.parent
+}
+
+func (l *listItem) Timestamp(v time.Time) *list {
+ l.parent.values = append(l.parent.values, value.TimestampValueFromTime(v))
+
+ return l.parent
+}
+
+func (l *listItem) Date(v time.Time) *list {
+ l.parent.values = append(l.parent.values, value.DateValueFromTime(v))
+
+ return l.parent
+}
+
+func (l *listItem) Datetime(v time.Time) *list {
+ l.parent.values = append(l.parent.values, value.DatetimeValueFromTime(v))
+
+ return l.parent
+}
+
+func (l *listItem) Interval(v time.Duration) *list {
+ l.parent.values = append(l.parent.values, value.IntervalValueFromDuration(v))
+
+ return l.parent
+}
+
+func (l *listItem) JSON(v string) *list {
+ l.parent.values = append(l.parent.values, value.JSONValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) JSONDocument(v string) *list {
+ l.parent.values = append(l.parent.values, value.JSONDocumentValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) YSON(v []byte) *list {
+ l.parent.values = append(l.parent.values, value.YSONValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) UUID(v [16]byte) *list {
+ l.parent.values = append(l.parent.values, value.UUIDValue(v))
+
+ return l.parent
+}
+
+func (l *listItem) TzDate(v time.Time) *list {
+ l.parent.values = append(l.parent.values, value.TzDateValueFromTime(v))
+
+ return l.parent
+}
+
+func (l *listItem) TzTimestamp(v time.Time) *list {
+ l.parent.values = append(l.parent.values, value.TzTimestampValueFromTime(v))
+
+ return l.parent
+}
+
+func (l *listItem) TzDatetime(v time.Time) *list {
+ l.parent.values = append(l.parent.values, value.TzDatetimeValueFromTime(v))
+
+ return l.parent
+}
diff --git a/internal/params/list_test.go b/internal/params/list_test.go
new file mode 100644
index 000000000..153212f89
--- /dev/null
+++ b/internal/params/list_test.go
@@ -0,0 +1,475 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestList(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ args: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int64",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ args: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int32",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ args: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int16",
+ args: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ args: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int8",
+ args: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Bool",
+ args: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ {
+ method: "Text",
+ args: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ args: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ {
+ method: "Float",
+ args: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Double",
+ args: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Interval",
+ args: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ {
+ method: "Date",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ {
+ method: "JSON",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "YSON",
+ args: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ },
+ },
+ },
+ {
+ method: "UUID",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginList().Add()
+
+ result, ok := xtest.CallMethod(item, tc.method, tc.args...)[0].(*list)
+ require.True(t, ok)
+
+ params := result.EndList().Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_ListType{
+ ListType: &Ydb.ListType{
+ Item: tc.expected.Type,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ tc.expected.Value,
+ },
+ },
+ },
+ }), paramsToJSON(params))
+ })
+ }
+}
+
+func TestList_AddItems(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ params := Builder{}.Param("$x").BeginList().
+ AddItems(value.Uint64Value(123), value.Uint64Value(321)).
+ EndList().Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_ListType{
+ ListType: &Ydb.ListType{
+ Item: &Ydb.Type{Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64}},
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 321,
+ },
+ },
+ },
+ },
+ },
+ }), paramsToJSON(params))
+}
diff --git a/internal/params/optional.go b/internal/params/optional.go
new file mode 100644
index 000000000..f5aa02efb
--- /dev/null
+++ b/internal/params/optional.go
@@ -0,0 +1,178 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ optional struct {
+ parent Builder
+ name string
+ value value.Value
+ }
+ optionalBuilder struct {
+ opt *optional
+ }
+)
+
+func (b *optionalBuilder) EndOptional() Builder {
+ b.opt.parent.params = append(b.opt.parent.params, &Parameter{
+ parent: b.opt.parent,
+ name: b.opt.name,
+ value: value.OptionalValue(b.opt.value),
+ })
+
+ return b.opt.parent
+}
+
+func (p *optional) Text(v string) *optionalBuilder {
+ p.value = value.TextValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Bytes(v []byte) *optionalBuilder {
+ p.value = value.BytesValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Bool(v bool) *optionalBuilder {
+ p.value = value.BoolValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Uint64(v uint64) *optionalBuilder {
+ p.value = value.Uint64Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Int64(v int64) *optionalBuilder {
+ p.value = value.Int64Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Uint32(v uint32) *optionalBuilder {
+ p.value = value.Uint32Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Int32(v int32) *optionalBuilder {
+ p.value = value.Int32Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Uint16(v uint16) *optionalBuilder {
+ p.value = value.Uint16Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Int16(v int16) *optionalBuilder {
+ p.value = value.Int16Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Uint8(v uint8) *optionalBuilder {
+ p.value = value.Uint8Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Int8(v int8) *optionalBuilder {
+ p.value = value.Int8Value(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Float(v float32) *optionalBuilder {
+ p.value = value.FloatValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Double(v float64) *optionalBuilder {
+ p.value = value.DoubleValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Decimal(v [16]byte, precision, scale uint32) *optionalBuilder {
+ p.value = value.DecimalValue(v, precision, scale)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Timestamp(v time.Time) *optionalBuilder {
+ p.value = value.TimestampValueFromTime(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Date(v time.Time) *optionalBuilder {
+ p.value = value.DateValueFromTime(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Datetime(v time.Time) *optionalBuilder {
+ p.value = value.DatetimeValueFromTime(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) Interval(v time.Duration) *optionalBuilder {
+ p.value = value.IntervalValueFromDuration(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) JSON(v string) *optionalBuilder {
+ p.value = value.JSONValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) JSONDocument(v string) *optionalBuilder {
+ p.value = value.JSONDocumentValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) YSON(v []byte) *optionalBuilder {
+ p.value = value.YSONValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) UUID(v [16]byte) *optionalBuilder {
+ p.value = value.UUIDValue(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) TzDate(v time.Time) *optionalBuilder {
+ p.value = value.TzDateValueFromTime(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) TzTimestamp(v time.Time) *optionalBuilder {
+ p.value = value.TzTimestampValueFromTime(v)
+
+ return &optionalBuilder{opt: p}
+}
+
+func (p *optional) TzDatetime(v time.Time) *optionalBuilder {
+ p.value = value.TzDatetimeValueFromTime(v)
+
+ return &optionalBuilder{opt: p}
+}
diff --git a/internal/params/optional_test.go b/internal/params/optional_test.go
new file mode 100644
index 000000000..37246e364
--- /dev/null
+++ b/internal/params/optional_test.go
@@ -0,0 +1,436 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestOptional(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ args: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int64",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ args: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int32",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ args: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int16",
+ args: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ args: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int8",
+ args: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Bool",
+ args: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ {
+ method: "Text",
+ args: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ args: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ {
+ method: "Float",
+ args: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Double",
+ args: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Interval",
+ args: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ {
+ method: "Date",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ {
+ method: "JSON",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "YSON",
+ args: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ },
+ },
+ },
+ {
+ method: "UUID",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginOptional()
+
+ result, ok := xtest.CallMethod(item, tc.method, tc.args...)[0].(*optionalBuilder)
+ require.True(t, ok)
+
+ params := result.EndOptional().Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_OptionalType{
+ OptionalType: &Ydb.OptionalType{
+ Item: tc.expected.Type,
+ },
+ },
+ },
+ Value: tc.expected.Value,
+ },
+ }), paramsToJSON(params))
+ })
+ }
+}
diff --git a/internal/params/parameters.go b/internal/params/parameters.go
new file mode 100644
index 000000000..7faa23041
--- /dev/null
+++ b/internal/params/parameters.go
@@ -0,0 +1,325 @@
+package params
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
+)
+
+type (
+ NamedValue interface {
+ Name() string
+ Value() value.Value
+ }
+ Parameter struct {
+ parent Builder
+ name string
+ value value.Value
+ }
+ Parameters []*Parameter
+)
+
+func Named(name string, value value.Value) *Parameter {
+ return &Parameter{
+ name: name,
+ value: value,
+ }
+}
+
+func (p *Parameter) Name() string {
+ return p.name
+}
+
+func (p *Parameter) Value() value.Value {
+ return p.value
+}
+
+func (p *Parameters) String() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+
+ buffer.WriteByte('{')
+ if p != nil {
+ for i, param := range *p {
+ if i != 0 {
+ buffer.WriteByte(',')
+ }
+ buffer.WriteByte('"')
+ buffer.WriteString(param.name)
+ buffer.WriteString("\":")
+ buffer.WriteString(param.value.Yql())
+ }
+ }
+ buffer.WriteByte('}')
+
+ return buffer.String()
+}
+
+func (p *Parameters) ToYDB(a *allocator.Allocator) map[string]*Ydb.TypedValue {
+ if p == nil {
+ return nil
+ }
+ parameters := make(map[string]*Ydb.TypedValue, len(*p))
+ for _, param := range *p {
+ parameters[param.name] = value.ToYDB(param.value, a)
+ }
+
+ return parameters
+}
+
+func (p *Parameters) Each(it func(name string, v value.Value)) {
+ if p == nil {
+ return
+ }
+ for _, p := range *p {
+ it(p.name, p.value)
+ }
+}
+
+func (p *Parameters) Count() int {
+ if p == nil {
+ return 0
+ }
+
+ return len(*p)
+}
+
+func (p *Parameters) Add(params ...NamedValue) {
+ for _, param := range params {
+ *p = append(*p, Named(param.Name(), param.Value()))
+ }
+}
+
+func (p *Parameter) BeginOptional() *optional {
+ return &optional{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) BeginList() *list {
+ return &list{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) Pg() pgParam {
+ return pgParam{p}
+}
+
+func (p *Parameter) BeginSet() *set {
+ return &set{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) BeginDict() *dict {
+ return &dict{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) BeginTuple() *tuple {
+ return &tuple{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) BeginStruct() *structure {
+ return &structure{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) Text(v string) Builder {
+ p.value = value.TextValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Bytes(v []byte) Builder {
+ p.value = value.BytesValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Bool(v bool) Builder {
+ p.value = value.BoolValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Uint64(v uint64) Builder {
+ p.value = value.Uint64Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Int64(v int64) Builder {
+ p.value = value.Int64Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Uint32(v uint32) Builder {
+ p.value = value.Uint32Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Int32(v int32) Builder {
+ p.value = value.Int32Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Uint16(v uint16) Builder {
+ p.value = value.Uint16Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Int16(v int16) Builder {
+ p.value = value.Int16Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Uint8(v uint8) Builder {
+ p.value = value.Uint8Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Int8(v int8) Builder {
+ p.value = value.Int8Value(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Float(v float32) Builder {
+ p.value = value.FloatValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Double(v float64) Builder {
+ p.value = value.DoubleValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Decimal(v [16]byte, precision, scale uint32) Builder {
+ p.value = value.DecimalValue(v, precision, scale)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Timestamp(v time.Time) Builder {
+ p.value = value.TimestampValueFromTime(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Date(v time.Time) Builder {
+ p.value = value.DateValueFromTime(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Datetime(v time.Time) Builder {
+ p.value = value.DatetimeValueFromTime(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) Interval(v time.Duration) Builder {
+ p.value = value.IntervalValueFromDuration(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) JSON(v string) Builder {
+ p.value = value.JSONValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) JSONDocument(v string) Builder {
+ p.value = value.JSONDocumentValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) YSON(v []byte) Builder {
+ p.value = value.YSONValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) UUID(v [16]byte) Builder {
+ p.value = value.UUIDValue(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) TzDate(v time.Time) Builder {
+ p.value = value.TzDateValueFromTime(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) TzTimestamp(v time.Time) Builder {
+ p.value = value.TzTimestampValueFromTime(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func (p *Parameter) TzDatetime(v time.Time) Builder {
+ p.value = value.TzDatetimeValueFromTime(v)
+ p.parent.params = append(p.parent.params, p)
+
+ return p.parent
+}
+
+func Declare(p *Parameter) string {
+ return fmt.Sprintf(
+ "DECLARE %s AS %s",
+ p.name,
+ p.value.Type().Yql(),
+ )
+}
diff --git a/internal/params/parameters_test.go b/internal/params/parameters_test.go
new file mode 100644
index 000000000..1c49c3f45
--- /dev/null
+++ b/internal/params/parameters_test.go
@@ -0,0 +1,70 @@
+package params
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestParameter(t *testing.T) {
+ p := Named("x", value.TextValue("X"))
+ require.Equal(t, "x", p.Name())
+ require.EqualValues(t, "X", p.Value())
+ require.Equal(t, "DECLARE x AS Utf8", Declare(p))
+}
+
+func TestParameters(t *testing.T) {
+ p := &Parameters{}
+ p.Add(
+ Named("x", value.TextValue("X")),
+ Named("y", value.TextValue("Y")),
+ )
+ require.Equal(t, "{\"x\":\"X\"u,\"y\":\"Y\"u}", p.String())
+ require.Equal(t, 2, p.Count())
+ visited := make(map[string]value.Value, 2)
+ p.Each(func(name string, v value.Value) {
+ visited[name] = v
+ })
+ require.Len(t, visited, 2)
+ require.EqualValues(t, map[string]value.Value{
+ "x": value.TextValue("X"),
+ "y": value.TextValue("Y"),
+ }, visited)
+}
+
+func TestNil(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ p *Parameters
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ p: nil,
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ p: &Parameters{},
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ p: Builder{}.Build(),
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ require.Equal(t, "{}", tt.p.String())
+ require.Equal(t, 0, tt.p.Count())
+ visited := make(map[string]value.Value, 1)
+ tt.p.Each(func(name string, v value.Value) {
+ visited[name] = v
+ })
+ require.Empty(t, visited)
+ a := allocator.New()
+ defer a.Free()
+ require.Empty(t, tt.p.ToYDB(a))
+ })
+ }
+}
diff --git a/internal/params/pg.go b/internal/params/pg.go
new file mode 100644
index 000000000..542957859
--- /dev/null
+++ b/internal/params/pg.go
@@ -0,0 +1,31 @@
+package params
+
+import (
+ "strconv"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pg"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type pgParam struct {
+ param *Parameter
+}
+
+func (p pgParam) Unknown(val string) Builder {
+ return p.Value(pg.OIDUnknown, val)
+}
+
+func (p pgParam) Value(oid uint32, val string) Builder {
+ p.param.value = value.PgValue(oid, val)
+ p.param.parent.params = append(p.param.parent.params, p.param)
+
+ return p.param.parent
+}
+
+func (p pgParam) Int4(val int32) Builder {
+ return p.Value(pg.OIDInt4, strconv.FormatInt(int64(val), 10))
+}
+
+func (p pgParam) Int8(val int64) Builder {
+ return p.Value(pg.OIDInt8, strconv.FormatInt(val, 10))
+}
diff --git a/internal/params/pg_test.go b/internal/params/pg_test.go
new file mode 100644
index 000000000..4fc6f15f1
--- /dev/null
+++ b/internal/params/pg_test.go
@@ -0,0 +1,100 @@
+package params
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pg"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestPg(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
+ }{
+ {
+ method: "Unknown",
+ args: []any{"123"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_PgType{
+ PgType: &Ydb.PgType{
+ Oid: pg.OIDUnknown,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{TextValue: "123"},
+ },
+ },
+ },
+ {
+ method: "Int4",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_PgType{
+ PgType: &Ydb.PgType{
+ Oid: pg.OIDInt4,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{TextValue: "123"},
+ },
+ },
+ },
+ {
+ method: "Int8",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_PgType{
+ PgType: &Ydb.PgType{
+ Oid: pg.OIDInt8,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{TextValue: "123"},
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").Pg()
+
+ result, ok := xtest.CallMethod(item, tc.method, tc.args...)[0].(Builder)
+ require.True(t, ok)
+
+ params := result.Build().ToYDB(a)
+
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: tc.expected.Type,
+ Value: tc.expected.Value,
+ },
+ }), paramsToJSON(params))
+ })
+ }
+}
diff --git a/internal/params/set.go b/internal/params/set.go
new file mode 100644
index 000000000..cb2303fde
--- /dev/null
+++ b/internal/params/set.go
@@ -0,0 +1,191 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ set struct {
+ parent Builder
+ name string
+ values []value.Value
+ }
+
+ setItem struct {
+ parent *set
+ }
+)
+
+func (s *set) Add() *setItem {
+ return &setItem{
+ parent: s,
+ }
+}
+
+func (s *set) AddItems(items ...value.Value) *set {
+ s.values = append(s.values, items...)
+
+ return s
+}
+
+func (s *set) EndSet() Builder {
+ s.parent.params = append(s.parent.params, &Parameter{
+ parent: s.parent,
+ name: s.name,
+ value: value.SetValue(s.values...),
+ })
+
+ return s.parent
+}
+
+func (s *setItem) Text(v string) *set {
+ s.parent.values = append(s.parent.values, value.TextValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) Bytes(v []byte) *set {
+ s.parent.values = append(s.parent.values, value.BytesValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) Bool(v bool) *set {
+ s.parent.values = append(s.parent.values, value.BoolValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) Uint64(v uint64) *set {
+ s.parent.values = append(s.parent.values, value.Uint64Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Int64(v int64) *set {
+ s.parent.values = append(s.parent.values, value.Int64Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Uint32(v uint32) *set {
+ s.parent.values = append(s.parent.values, value.Uint32Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Int32(v int32) *set {
+ s.parent.values = append(s.parent.values, value.Int32Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Uint16(v uint16) *set {
+ s.parent.values = append(s.parent.values, value.Uint16Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Int16(v int16) *set {
+ s.parent.values = append(s.parent.values, value.Int16Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Uint8(v uint8) *set {
+ s.parent.values = append(s.parent.values, value.Uint8Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Int8(v int8) *set {
+ s.parent.values = append(s.parent.values, value.Int8Value(v))
+
+ return s.parent
+}
+
+func (s *setItem) Float(v float32) *set {
+ s.parent.values = append(s.parent.values, value.FloatValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) Double(v float64) *set {
+ s.parent.values = append(s.parent.values, value.DoubleValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) Decimal(v [16]byte, precision, scale uint32) *set {
+ s.parent.values = append(s.parent.values, value.DecimalValue(v, precision, scale))
+
+ return s.parent
+}
+
+func (s *setItem) Timestamp(v time.Time) *set {
+ s.parent.values = append(s.parent.values, value.TimestampValueFromTime(v))
+
+ return s.parent
+}
+
+func (s *setItem) Date(v time.Time) *set {
+ s.parent.values = append(s.parent.values, value.DateValueFromTime(v))
+
+ return s.parent
+}
+
+func (s *setItem) Datetime(v time.Time) *set {
+ s.parent.values = append(s.parent.values, value.DatetimeValueFromTime(v))
+
+ return s.parent
+}
+
+func (s *setItem) Interval(v time.Duration) *set {
+ s.parent.values = append(s.parent.values, value.IntervalValueFromDuration(v))
+
+ return s.parent
+}
+
+func (s *setItem) JSON(v string) *set {
+ s.parent.values = append(s.parent.values, value.JSONValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) JSONDocument(v string) *set {
+ s.parent.values = append(s.parent.values, value.JSONDocumentValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) YSON(v []byte) *set {
+ s.parent.values = append(s.parent.values, value.YSONValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) UUID(v [16]byte) *set {
+ s.parent.values = append(s.parent.values, value.UUIDValue(v))
+
+ return s.parent
+}
+
+func (s *setItem) TzDate(v time.Time) *set {
+ s.parent.values = append(s.parent.values, value.TzDateValueFromTime(v))
+
+ return s.parent
+}
+
+func (s *setItem) TzTimestamp(v time.Time) *set {
+ s.parent.values = append(s.parent.values, value.TzTimestampValueFromTime(v))
+
+ return s.parent
+}
+
+func (s *setItem) TzDatetime(v time.Time) *set {
+ s.parent.values = append(s.parent.values, value.TzDatetimeValueFromTime(v))
+
+ return s.parent
+}
diff --git a/internal/params/set_test.go b/internal/params/set_test.go
new file mode 100644
index 000000000..0a97b866b
--- /dev/null
+++ b/internal/params/set_test.go
@@ -0,0 +1,500 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestSet(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ args: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int64",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ args: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int32",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ args: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int16",
+ args: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ args: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Int8",
+ args: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ {
+ method: "Bool",
+ args: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ {
+ method: "Text",
+ args: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ args: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ {
+ method: "Float",
+ args: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Double",
+ args: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ },
+ },
+ },
+ {
+ method: "Interval",
+ args: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ {
+ method: "Date",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ {
+ method: "JSON",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ {
+ method: "YSON",
+ args: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ },
+ },
+ },
+ {
+ method: "UUID",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginSet().Add()
+
+ result, ok := xtest.CallMethod(item, tc.method, tc.args...)[0].(*set)
+ require.True(t, ok)
+
+ params := result.EndSet().Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DictType{
+ DictType: &Ydb.DictType{
+ Key: tc.expected.Type,
+ Payload: &Ydb.Type{
+ Type: &Ydb.Type_VoidType{},
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Pairs: []*Ydb.ValuePair{
+ {
+ Key: tc.expected.Value,
+ Payload: &Ydb.Value{
+ Value: &Ydb.Value_NullFlagValue{},
+ },
+ },
+ },
+ },
+ },
+ }), paramsToJSON(params))
+ })
+ }
+}
+
+func TestSet_AddItems(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ params := Builder{}.Param("$x").BeginSet().
+ AddItems(value.Uint64Value(123), value.Uint64Value(321)).
+ EndSet().Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DictType{
+ DictType: &Ydb.DictType{
+ Key: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ Payload: &Ydb.Type{
+ Type: &Ydb.Type_VoidType{},
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Pairs: []*Ydb.ValuePair{
+ {
+ Key: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ Payload: &Ydb.Value{
+ Value: &Ydb.Value_NullFlagValue{},
+ },
+ },
+ {
+ Key: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 321,
+ },
+ },
+ Payload: &Ydb.Value{
+ Value: &Ydb.Value_NullFlagValue{},
+ },
+ },
+ },
+ },
+ },
+ }), paramsToJSON(params))
+}
diff --git a/internal/params/struct.go b/internal/params/struct.go
new file mode 100644
index 000000000..0a8af589b
--- /dev/null
+++ b/internal/params/struct.go
@@ -0,0 +1,268 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ structure struct {
+ parent Builder
+ name string
+ values []value.StructValueField
+ }
+
+ structValue struct {
+ parent *structure
+ name string
+ }
+)
+
+func (s *structure) AddItems(items ...value.StructValueField) *structure {
+ s.values = append(s.values, items...)
+
+ return s
+}
+
+func (s *structure) Field(v string) *structValue {
+ return &structValue{
+ parent: s,
+ name: v,
+ }
+}
+
+func (s *structure) EndStruct() Builder {
+ s.parent.params = append(s.parent.params, &Parameter{
+ parent: s.parent,
+ name: s.name,
+ value: value.StructValue(s.values...),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Text(v string) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TextValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Bytes(v []byte) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.BytesValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Bool(v bool) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.BoolValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint64(v uint64) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint64Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int64(v int64) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int64Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint32(v uint32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint32Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int32(v int32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int32Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint16(v uint16) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint16Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int16(v int16) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int16Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint8(v uint8) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint8Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int8(v int8) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int8Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Float(v float32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.FloatValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Double(v float64) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DoubleValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Decimal(v [16]byte, precision, scale uint32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DecimalValue(v, precision, scale),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Timestamp(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TimestampValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Date(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DateValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Datetime(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DatetimeValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Interval(v time.Duration) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.IntervalValueFromDuration(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) JSON(v string) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.JSONValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) JSONDocument(v string) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.JSONDocumentValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) YSON(v []byte) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.YSONValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) UUID(v [16]byte) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.UUIDValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) TzDatetime(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TzDatetimeValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) TzTimestamp(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TzTimestampValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) TzDate(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TzDateValueFromTime(v),
+ })
+
+ return s.parent
+}
diff --git a/internal/params/struct_test.go b/internal/params/struct_test.go
new file mode 100644
index 000000000..d4aac1775
--- /dev/null
+++ b/internal/params/struct_test.go
@@ -0,0 +1,922 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestStruct(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ builder Builder
+ params map[string]*Ydb.TypedValue
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint64(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int64(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint32(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int32(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint16(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int16(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint8(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int8(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Bool(true).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Text("test").EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Bytes([]byte("test")).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Float(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_FLOAT,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Double(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DOUBLE,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Interval(time.Second).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INTERVAL,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Datetime(time.Unix(123456789, 456)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATETIME,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Date(time.Unix(123456789, 456)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATE,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Timestamp(time.Unix(123456789, 456)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TIMESTAMP,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Decimal([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9).EndStruct(), //nolint:lll
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").JSON(`{"a": 1,"b": "B"}`).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_JSON,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").JSONDocument(`{"a": 1,"b": "B"}`).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_JSON_DOCUMENT,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").YSON([]byte(`[ 1; 2; 3; 4; 5 ]`)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_YSON,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`[ 1; 2; 3; 4; 5 ]`),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").
+ UUID([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UUID,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().
+ Field("col1").Text("text").
+ Field("col2").Uint32(123).
+ Field("col3").Int64(456).
+ EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "col2",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ {
+ Name: "col3",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "text",
+ },
+ },
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 456,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").TzDatetime(time.Unix(123456789, 456).UTC()).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TZ_DATETIME,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").TzDate(time.Unix(123456789, 456).UTC()).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TZ_DATE,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").TzTimestamp(time.Unix(123456789, 456).UTC()).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TZ_TIMESTAMP,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ params := tt.builder.Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(tt.params), paramsToJSON(params))
+ })
+ }
+}
diff --git a/internal/params/tuple.go b/internal/params/tuple.go
new file mode 100644
index 000000000..0762cdb05
--- /dev/null
+++ b/internal/params/tuple.go
@@ -0,0 +1,172 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ tuple struct {
+ parent Builder
+ name string
+ values []value.Value
+ }
+ tupleItem struct {
+ parent *tuple
+ }
+)
+
+func (t *tuple) Add() *tupleItem {
+ return &tupleItem{
+ parent: t,
+ }
+}
+
+func (t *tuple) AddItems(items ...value.Value) *tuple {
+ t.values = append(t.values, items...)
+
+ return t
+}
+
+func (t *tuple) EndTuple() Builder {
+ t.parent.params = append(t.parent.params, &Parameter{
+ parent: t.parent,
+ name: t.name,
+ value: value.TupleValue(t.values...),
+ })
+
+ return t.parent
+}
+
+func (t *tupleItem) Text(v string) *tuple {
+ t.parent.values = append(t.parent.values, value.TextValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Bytes(v []byte) *tuple {
+ t.parent.values = append(t.parent.values, value.BytesValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Bool(v bool) *tuple {
+ t.parent.values = append(t.parent.values, value.BoolValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Uint64(v uint64) *tuple {
+ t.parent.values = append(t.parent.values, value.Uint64Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Int64(v int64) *tuple {
+ t.parent.values = append(t.parent.values, value.Int64Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Uint32(v uint32) *tuple {
+ t.parent.values = append(t.parent.values, value.Uint32Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Int32(v int32) *tuple {
+ t.parent.values = append(t.parent.values, value.Int32Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Uint16(v uint16) *tuple {
+ t.parent.values = append(t.parent.values, value.Uint16Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Int16(v int16) *tuple {
+ t.parent.values = append(t.parent.values, value.Int16Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Uint8(v uint8) *tuple {
+ t.parent.values = append(t.parent.values, value.Uint8Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Int8(v int8) *tuple {
+ t.parent.values = append(t.parent.values, value.Int8Value(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Float(v float32) *tuple {
+ t.parent.values = append(t.parent.values, value.FloatValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Double(v float64) *tuple {
+ t.parent.values = append(t.parent.values, value.DoubleValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Decimal(v [16]byte, precision, scale uint32) *tuple {
+ t.parent.values = append(t.parent.values, value.DecimalValue(v, precision, scale))
+
+ return t.parent
+}
+
+func (t *tupleItem) Timestamp(v time.Time) *tuple {
+ t.parent.values = append(t.parent.values, value.TimestampValueFromTime(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Date(v time.Time) *tuple {
+ t.parent.values = append(t.parent.values, value.DateValueFromTime(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Datetime(v time.Time) *tuple {
+ t.parent.values = append(t.parent.values, value.DatetimeValueFromTime(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) Interval(v time.Duration) *tuple {
+ t.parent.values = append(t.parent.values, value.IntervalValueFromDuration(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) JSON(v string) *tuple {
+ t.parent.values = append(t.parent.values, value.JSONValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) JSONDocument(v string) *tuple {
+ t.parent.values = append(t.parent.values, value.JSONDocumentValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) YSON(v []byte) *tuple {
+ t.parent.values = append(t.parent.values, value.YSONValue(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) UUID(v [16]byte) *tuple {
+ t.parent.values = append(t.parent.values, value.UUIDValue(v))
+
+ return t.parent
+}
diff --git a/internal/params/tuple_test.go b/internal/params/tuple_test.go
new file mode 100644
index 000000000..9938fae0c
--- /dev/null
+++ b/internal/params/tuple_test.go
@@ -0,0 +1,735 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestTuple(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ builder Builder
+ params map[string]*Ydb.TypedValue
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Uint64(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Int64(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Uint32(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Int32(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Uint16(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Int16(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Uint8(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT8,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Int8(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT8,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Bool(true).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Text("test").EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Bytes([]byte("test")).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Float(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_FLOAT,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Double(123).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DOUBLE,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Interval(time.Second).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INTERVAL,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Datetime(time.Unix(123456789, 456)).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATETIME,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Date(time.Unix(123456789, 456)).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATE,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Timestamp(time.Unix(123456789, 456)).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TIMESTAMP,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().Decimal([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9).EndTuple(), //nolint:lll
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().JSON(`{"a": 1,"b": "B"}`).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_JSON,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().JSONDocument(`{"a": 1,"b": "B"}`).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_JSON_DOCUMENT,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().YSON([]byte(`[ 1; 2; 3; 4; 5 ]`)).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_YSON,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`[ 1; 2; 3; 4; 5 ]`),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().Add().
+ UUID([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UUID,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginTuple().AddItems(value.Uint64Value(123), value.Uint64Value(321)).EndTuple(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 321,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ params := tt.builder.Build().ToYDB(a)
+ require.Equal(t, paramsToJSON(tt.params), paramsToJSON(params))
+ })
+ }
+}
diff --git a/internal/pg/pgconst.go b/internal/pg/pgconst.go
new file mode 100644
index 000000000..f6a8273c8
--- /dev/null
+++ b/internal/pg/pgconst.go
@@ -0,0 +1,9 @@
+package pg
+
+const (
+ // https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
+
+ OIDInt4 = 23
+ OIDInt8 = 20
+ OIDUnknown = 705
+)
diff --git a/internal/pool/defaults.go b/internal/pool/defaults.go
new file mode 100644
index 000000000..2591e8438
--- /dev/null
+++ b/internal/pool/defaults.go
@@ -0,0 +1,31 @@
+package pool
+
+const DefaultLimit = 50
+
+var defaultTrace = &Trace{
+ OnNew: func(info *NewStartInfo) func(info *NewDoneInfo) {
+ return func(info *NewDoneInfo) {
+ }
+ },
+ OnClose: func(info *CloseStartInfo) func(info *CloseDoneInfo) {
+ return func(info *CloseDoneInfo) {
+ }
+ },
+ OnTry: func(info *TryStartInfo) func(info *TryDoneInfo) {
+ return func(info *TryDoneInfo) {
+ }
+ },
+ OnWith: func(info *WithStartInfo) func(info *WithDoneInfo) {
+ return func(info *WithDoneInfo) {
+ }
+ },
+ OnPut: func(info *PutStartInfo) func(info *PutDoneInfo) {
+ return func(info *PutDoneInfo) {
+ }
+ },
+ OnGet: func(info *GetStartInfo) func(info *GetDoneInfo) {
+ return func(info *GetDoneInfo) {
+ }
+ },
+ OnChange: func(info ChangeInfo) {},
+}
diff --git a/internal/pool/errors.go b/internal/pool/errors.go
new file mode 100644
index 000000000..36b6526c7
--- /dev/null
+++ b/internal/pool/errors.go
@@ -0,0 +1,10 @@
+package pool
+
+import (
+ "errors"
+)
+
+var (
+ errClosedPool = errors.New("closed pool")
+ errItemIsNotAlive = errors.New("item is not alive")
+)
diff --git a/internal/pool/pool.go b/internal/pool/pool.go
new file mode 100644
index 000000000..b7a5e8a3f
--- /dev/null
+++ b/internal/pool/pool.go
@@ -0,0 +1,484 @@
+package pool
+
+import (
+ "context"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool/stats"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
+ "github.com/ydb-platform/ydb-go-sdk/v3/retry"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+type (
+ Item[T any] interface {
+ *T
+ IsAlive() bool
+ Close(ctx context.Context) error
+ }
+ safeStats struct {
+ mu xsync.RWMutex
+ v stats.Stats
+ onChange func(stats.Stats)
+ }
+ statsItemAddr struct {
+ v *int
+ onChange func(func())
+ }
+ Pool[PT Item[T], T any] struct {
+ trace *Trace
+ limit int
+
+ createItem func(ctx context.Context) (PT, error)
+ createTimeout time.Duration
+ closeTimeout time.Duration
+
+ mu xsync.Mutex
+ idle []PT
+ index map[PT]struct{}
+ done chan struct{}
+
+ stats *safeStats
+ }
+ option[PT Item[T], T any] func(p *Pool[PT, T])
+)
+
+func (field statsItemAddr) Inc() {
+ field.onChange(func() {
+ *field.v++
+ })
+}
+
+func (field statsItemAddr) Dec() {
+ field.onChange(func() {
+ *field.v--
+ })
+}
+
+func (s *safeStats) Get() stats.Stats {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return s.v
+}
+
+func (s *safeStats) Index() statsItemAddr {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return statsItemAddr{
+ v: &s.v.Index,
+ onChange: func(f func()) {
+ s.mu.WithLock(f)
+ if s.onChange != nil {
+ s.onChange(s.Get())
+ }
+ },
+ }
+}
+
+func (s *safeStats) Idle() statsItemAddr {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return statsItemAddr{
+ v: &s.v.Idle,
+ onChange: func(f func()) {
+ s.mu.WithLock(f)
+ if s.onChange != nil {
+ s.onChange(s.Get())
+ }
+ },
+ }
+}
+
+func (s *safeStats) InUse() statsItemAddr {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return statsItemAddr{
+ v: &s.v.InUse,
+ onChange: func(f func()) {
+ s.mu.WithLock(f)
+ if s.onChange != nil {
+ s.onChange(s.Get())
+ }
+ },
+ }
+}
+
+func WithCreateFunc[PT Item[T], T any](f func(ctx context.Context) (PT, error)) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.createItem = f
+ }
+}
+
+func WithCreateItemTimeout[PT Item[T], T any](t time.Duration) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.createTimeout = t
+ }
+}
+
+func WithCloseItemTimeout[PT Item[T], T any](t time.Duration) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.closeTimeout = t
+ }
+}
+
+func WithLimit[PT Item[T], T any](size int) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.limit = size
+ }
+}
+
+func WithTrace[PT Item[T], T any](t *Trace) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.trace = t
+ }
+}
+
+func New[PT Item[T], T any](
+ ctx context.Context,
+ opts ...option[PT, T],
+) *Pool[PT, T] {
+ p := &Pool[PT, T]{
+ trace: defaultTrace,
+ limit: DefaultLimit,
+ createItem: func(ctx context.Context) (PT, error) {
+ var item T
+
+ return &item, nil
+ },
+ done: make(chan struct{}),
+ }
+
+ for _, opt := range opts {
+ if opt != nil {
+ opt(p)
+ }
+ }
+
+ onDone := p.trace.OnNew(&NewStartInfo{
+ Context: &ctx,
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.New"),
+ })
+
+ defer func() {
+ onDone(&NewDoneInfo{
+ Limit: p.limit,
+ })
+ }()
+
+ createItem := p.createItem
+
+ p.createItem = func(ctx context.Context) (PT, error) {
+ var (
+ ch = make(chan PT)
+ createErr error
+ )
+ go func() {
+ defer close(ch)
+ createErr = func() error {
+ var (
+ createCtx = xcontext.ValueOnly(ctx)
+ cancelCreate context.CancelFunc
+ )
+ if d := p.createTimeout; d > 0 {
+ createCtx, cancelCreate = xcontext.WithTimeout(createCtx, d)
+ } else {
+ createCtx, cancelCreate = xcontext.WithCancel(createCtx)
+ }
+ defer cancelCreate()
+
+ newItem, err := createItem(createCtx)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ needCloseItem := true
+ defer func() {
+ if needCloseItem {
+ _ = p.closeItem(ctx, newItem)
+ }
+ }()
+
+ select {
+ case <-p.done:
+ return xerrors.WithStackTrace(errClosedPool)
+
+ case <-ctx.Done():
+ p.mu.Lock()
+ defer p.mu.Unlock()
+
+ if len(p.index) < p.limit {
+ p.idle = append(p.idle, newItem)
+ p.index[newItem] = struct{}{}
+ p.stats.Index().Inc()
+ needCloseItem = false
+ }
+
+ return xerrors.WithStackTrace(ctx.Err())
+
+ case ch <- newItem:
+ needCloseItem = false
+
+ return nil
+ }
+ }()
+ }()
+
+ select {
+ case <-p.done:
+ return nil, xerrors.WithStackTrace(errClosedPool)
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ case item, has := <-ch:
+ if !has {
+ if ctxErr := ctx.Err(); ctxErr == nil && xerrors.IsContextError(createErr) {
+ return nil, xerrors.WithStackTrace(xerrors.Retryable(createErr))
+ }
+
+ return nil, xerrors.WithStackTrace(createErr)
+ }
+
+ return item, nil
+ }
+ }
+ p.idle = make([]PT, 0, p.limit)
+ p.index = make(map[PT]struct{}, p.limit)
+ p.stats = &safeStats{
+ v: stats.Stats{Limit: p.limit},
+ onChange: p.trace.OnChange,
+ }
+
+ return p
+}
+
+func (p *Pool[PT, T]) Stats() stats.Stats {
+ return p.stats.Get()
+}
+
+func (p *Pool[PT, T]) getItem(ctx context.Context) (_ PT, finalErr error) {
+ onDone := p.trace.OnGet(&GetStartInfo{
+ Context: &ctx,
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).getItem"),
+ })
+ defer func() {
+ onDone(&GetDoneInfo{
+ Error: finalErr,
+ })
+ }()
+
+ if err := ctx.Err(); err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ select {
+ case <-p.done:
+ return nil, xerrors.WithStackTrace(errClosedPool)
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ default:
+ var item PT
+ p.mu.WithLock(func() {
+ if len(p.idle) > 0 {
+ item, p.idle = p.idle[0], p.idle[1:]
+ p.stats.Idle().Dec()
+ }
+ })
+
+ if item != nil {
+ if item.IsAlive() {
+ return item, nil
+ }
+ _ = p.closeItem(ctx, item)
+ p.mu.WithLock(func() {
+ delete(p.index, item)
+ })
+ p.stats.Index().Dec()
+ }
+
+ item, err := p.createItem(ctx)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ addedToIndex := false
+ p.mu.WithLock(func() {
+ if len(p.index) < p.limit {
+ p.index[item] = struct{}{}
+ addedToIndex = true
+ }
+ })
+ if addedToIndex {
+ p.stats.Index().Inc()
+ }
+
+ return item, nil
+ }
+}
+
+func (p *Pool[PT, T]) putItem(ctx context.Context, item PT) (finalErr error) {
+ onDone := p.trace.OnPut(&PutStartInfo{
+ Context: &ctx,
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).putItem"),
+ })
+ defer func() {
+ onDone(&PutDoneInfo{
+ Error: finalErr,
+ })
+ }()
+
+ if err := ctx.Err(); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ select {
+ case <-p.done:
+ return xerrors.WithStackTrace(errClosedPool)
+ default:
+ if !item.IsAlive() {
+ _ = p.closeItem(ctx, item)
+
+ p.mu.WithLock(func() {
+ delete(p.index, item)
+ })
+ p.stats.Index().Dec()
+
+ return xerrors.WithStackTrace(errItemIsNotAlive)
+ }
+
+ p.mu.WithLock(func() {
+ p.idle = append(p.idle, item)
+ })
+ p.stats.Idle().Inc()
+
+ return nil
+ }
+}
+
+func (p *Pool[PT, T]) closeItem(ctx context.Context, item PT) error {
+ ctx = xcontext.ValueOnly(ctx)
+
+ var cancel context.CancelFunc
+ if d := p.closeTimeout; d > 0 {
+ ctx, cancel = xcontext.WithTimeout(ctx, d)
+ } else {
+ ctx, cancel = xcontext.WithCancel(ctx)
+ }
+ defer cancel()
+
+ return item.Close(ctx)
+}
+
+func (p *Pool[PT, T]) try(ctx context.Context, f func(ctx context.Context, item PT) error) (finalErr error) {
+ onDone := p.trace.OnTry(&TryStartInfo{
+ Context: &ctx,
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).try"),
+ })
+ defer func() {
+ onDone(&TryDoneInfo{
+ Error: finalErr,
+ })
+ }()
+
+ item, err := p.getItem(ctx)
+ if err != nil {
+ if xerrors.IsYdb(err) {
+ return xerrors.WithStackTrace(xerrors.Retryable(err))
+ }
+
+ return xerrors.WithStackTrace(err)
+ }
+
+ defer func() {
+ _ = p.putItem(ctx, item)
+ }()
+
+ p.stats.InUse().Inc()
+ defer p.stats.InUse().Dec()
+
+ err = f(ctx, item)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+func (p *Pool[PT, T]) With(
+ ctx context.Context,
+ f func(ctx context.Context, item PT) error,
+ opts ...retry.Option,
+) (finalErr error) {
+ var (
+ onDone = p.trace.OnWith(&WithStartInfo{
+ Context: &ctx,
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).With"),
+ })
+ attempts int
+ )
+ defer func() {
+ onDone(&WithDoneInfo{
+ Error: finalErr,
+ Attempts: attempts,
+ })
+ }()
+
+ err := retry.Retry(ctx, func(ctx context.Context) error {
+ err := p.try(ctx, f)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+ }, append(opts, retry.WithTrace(&trace.Retry{
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
+ }
+ },
+ }))...)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+func (p *Pool[PT, T]) Close(ctx context.Context) (finalErr error) {
+ onDone := p.trace.OnClose(&CloseStartInfo{
+ Context: &ctx,
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).Close"),
+ })
+ defer func() {
+ onDone(&CloseDoneInfo{
+ Error: finalErr,
+ })
+ }()
+
+ close(p.done)
+
+ p.mu.Lock()
+ defer p.mu.Unlock()
+
+ errs := make([]error, 0, len(p.index))
+
+ for item := range p.index {
+ if err := item.Close(ctx); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ switch len(errs) {
+ case 0:
+ return nil
+ case 1:
+ return errs[0]
+ default:
+ return xerrors.Join(errs...)
+ }
+}
diff --git a/internal/pool/pool_test.go b/internal/pool/pool_test.go
new file mode 100644
index 000000000..63f8a1c11
--- /dev/null
+++ b/internal/pool/pool_test.go
@@ -0,0 +1,320 @@
+package pool
+
+import (
+ "context"
+ "errors"
+ "math/rand"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+type testItem struct {
+ v uint32
+
+ onClose func() error
+ onIsAlive func() bool
+}
+
+func (t testItem) IsAlive() bool {
+ if t.onIsAlive != nil {
+ return t.onIsAlive()
+ }
+
+ return true
+}
+
+func (t testItem) ID() string {
+ return ""
+}
+
+func (t testItem) Close(context.Context) error {
+ if t.onClose != nil {
+ return t.onClose()
+ }
+
+ return nil
+}
+
+func TestPool(t *testing.T) {
+ rootCtx := xtest.Context(t)
+ t.Run("New", func(t *testing.T) {
+ t.Run("Default", func(t *testing.T) {
+ p := New[*testItem, testItem](rootCtx)
+ err := p.With(rootCtx, func(ctx context.Context, testItem *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ })
+ t.Run("WithLimit", func(t *testing.T) {
+ p := New[*testItem, testItem](rootCtx, WithLimit[*testItem, testItem](1))
+ require.EqualValues(t, 1, p.limit)
+ })
+ t.Run("WithCreateFunc", func(t *testing.T) {
+ var newCounter int64
+ p := New(rootCtx,
+ WithLimit[*testItem, testItem](1),
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&newCounter, 1)
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.EqualValues(t, p.limit, atomic.LoadInt64(&newCounter))
+ })
+ })
+ t.Run("Retry", func(t *testing.T) {
+ t.Run("CreateItem", func(t *testing.T) {
+ t.Run("context", func(t *testing.T) {
+ t.Run("Cancelled", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, context.Canceled
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ t.Run("DeadlineExceeded", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, context.DeadlineExceeded
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ })
+ t.Run("OnTransportError", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, ""))
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ t.Run("OnOperationError", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE))
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ })
+ })
+ t.Run("On", func(t *testing.T) {
+ t.Run("Context", func(t *testing.T) {
+ t.Run("Canceled", func(t *testing.T) {
+ ctx, cancel := context.WithCancel(rootCtx)
+ cancel()
+ p := New[*testItem, testItem](ctx, WithLimit[*testItem, testItem](1))
+ err := p.With(ctx, func(ctx context.Context, testItem *testItem) error {
+ return nil
+ })
+ require.ErrorIs(t, err, context.Canceled)
+ })
+ t.Run("DeadlineExceeded", func(t *testing.T) {
+ ctx, cancel := context.WithTimeout(rootCtx, 0)
+ cancel()
+ p := New[*testItem, testItem](ctx, WithLimit[*testItem, testItem](1))
+ err := p.With(ctx, func(ctx context.Context, testItem *testItem) error {
+ return nil
+ })
+ require.ErrorIs(t, err, context.DeadlineExceeded)
+ })
+ })
+ })
+ t.Run("Item", func(t *testing.T) {
+ t.Run("Close", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ var (
+ createCounter int64
+ closeCounter int64
+ )
+ p := New(rootCtx,
+ WithLimit[*testItem, testItem](1),
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&createCounter, 1)
+
+ v := &testItem{
+ onClose: func() error {
+ atomic.AddInt64(&closeCounter, 1)
+
+ return nil
+ },
+ }
+
+ return v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, testItem *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&createCounter), atomic.LoadInt64(&closeCounter))
+ err = p.Close(rootCtx)
+ require.NoError(t, err)
+ require.EqualValues(t, atomic.LoadInt64(&createCounter), atomic.LoadInt64(&closeCounter))
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("IsAlive", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ var (
+ newItems int64
+ deleteItems int64
+ expErr = xerrors.Retryable(errors.New("expected error"), xerrors.InvalidObject())
+ )
+ p := New(rootCtx,
+ WithLimit[*testItem, testItem](1),
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&newItems, 1)
+
+ v := &testItem{
+ onClose: func() error {
+ atomic.AddInt64(&deleteItems, 1)
+
+ return nil
+ },
+ onIsAlive: func() bool {
+ return atomic.LoadInt64(&newItems) >= 10
+ },
+ }
+
+ return v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, testItem *testItem) error {
+ if atomic.LoadInt64(&newItems) < 10 {
+ return expErr
+ }
+
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&newItems), int64(9))
+ require.GreaterOrEqual(t, atomic.LoadInt64(&newItems), atomic.LoadInt64(&deleteItems))
+ err = p.Close(rootCtx)
+ require.NoError(t, err)
+ require.EqualValues(t, atomic.LoadInt64(&newItems), atomic.LoadInt64(&deleteItems))
+ }, xtest.StopAfter(5*time.Second))
+ })
+ })
+ t.Run("Stress", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ p := New[*testItem, testItem](rootCtx)
+ var wg sync.WaitGroup
+ wg.Add(DefaultLimit*2 + 1)
+ for range make([]struct{}, DefaultLimit*2) {
+ go func() {
+ defer wg.Done()
+ err := p.With(rootCtx, func(ctx context.Context, testItem *testItem) error {
+ return nil
+ })
+ if err != nil && !xerrors.Is(err, errClosedPool, context.Canceled) {
+ t.Failed()
+ }
+ }()
+ }
+ go func() {
+ defer wg.Done()
+ time.Sleep(time.Millisecond)
+ err := p.Close(rootCtx)
+ require.NoError(t, err)
+ }()
+ wg.Wait()
+ }, xtest.StopAfter(42*time.Second))
+ })
+}
+
+func TestSafeStatsRace(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ var (
+ wg sync.WaitGroup
+ s = &safeStats{}
+ )
+ wg.Add(10000)
+ for range make([]struct{}, 10000) {
+ go func() {
+ defer wg.Done()
+ require.NotPanics(t, func() {
+ switch rand.Int31n(4) { //nolint:gosec
+ case 0:
+ s.Index().Inc()
+ case 1:
+ s.InUse().Inc()
+ case 2:
+ s.Idle().Inc()
+ default:
+ s.Get()
+ }
+ })
+ }()
+ }
+ wg.Wait()
+ }, xtest.StopAfter(5*time.Second))
+}
diff --git a/internal/pool/stats/stats.go b/internal/pool/stats/stats.go
new file mode 100644
index 000000000..dff03eaeb
--- /dev/null
+++ b/internal/pool/stats/stats.go
@@ -0,0 +1,8 @@
+package stats
+
+type Stats struct {
+ Limit int
+ Index int
+ Idle int
+ InUse int
+}
diff --git a/internal/pool/trace.go b/internal/pool/trace.go
new file mode 100644
index 000000000..40adef256
--- /dev/null
+++ b/internal/pool/trace.go
@@ -0,0 +1,89 @@
+package pool
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool/stats"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+)
+
+type (
+ Trace struct {
+ OnNew func(*NewStartInfo) func(*NewDoneInfo)
+ OnClose func(*CloseStartInfo) func(*CloseDoneInfo)
+ OnTry func(*TryStartInfo) func(*TryDoneInfo)
+ OnWith func(*WithStartInfo) func(*WithDoneInfo)
+ OnPut func(*PutStartInfo) func(*PutDoneInfo)
+ OnGet func(*GetStartInfo) func(*GetDoneInfo)
+ OnChange func(ChangeInfo)
+ }
+ NewStartInfo struct {
+ // Context make available context in trace stack.Callerback function.
+ // Pointer to context provide replacement of context in trace stack.Callerback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside stack.Callerback function
+ Context *context.Context
+ Call stack.Caller
+ }
+ NewDoneInfo struct {
+ Limit int
+ }
+ CloseStartInfo struct {
+ // Context make available context in trace stack.Callerback function.
+ // Pointer to context provide replacement of context in trace stack.Callerback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside stack.Callerback function
+ Context *context.Context
+ Call stack.Caller
+ }
+ CloseDoneInfo struct {
+ Error error
+ }
+ TryStartInfo struct {
+ // Context make available context in trace stack.Callerback function.
+ // Pointer to context provide replacement of context in trace stack.Callerback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside stack.Callerback function
+ Context *context.Context
+ Call stack.Caller
+ }
+ TryDoneInfo struct {
+ Error error
+ }
+ WithStartInfo struct {
+ // Context make available context in trace stack.Callerback function.
+ // Pointer to context provide replacement of context in trace stack.Callerback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside stack.Callerback function
+ Context *context.Context
+ Call stack.Caller
+ }
+ WithDoneInfo struct {
+ Error error
+
+ Attempts int
+ }
+ PutStartInfo struct {
+ // Context make available context in trace stack.Callerback function.
+ // Pointer to context provide replacement of context in trace stack.Callerback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside stack.Callerback function
+ Context *context.Context
+ Call stack.Caller
+ }
+ PutDoneInfo struct {
+ Error error
+ }
+ GetStartInfo struct {
+ // Context make available context in trace stack.Callerback function.
+ // Pointer to context provide replacement of context in trace stack.Callerback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside stack.Callerback function
+ Context *context.Context
+ Call stack.Caller
+ }
+ GetDoneInfo struct {
+ Error error
+ }
+ ChangeInfo = stats.Stats
+)
diff --git a/internal/query/client.go b/internal/query/client.go
new file mode 100644
index 000000000..3019e83cd
--- /dev/null
+++ b/internal/query/client.go
@@ -0,0 +1,262 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ "google.golang.org/grpc"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool/stats"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/retry"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+//go:generate mockgen -destination grpc_client_mock_test.go -package query -write_package_comment=false github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1 QueryServiceClient,QueryService_AttachSessionClient,QueryService_ExecuteQueryClient
+
+type nodeChecker interface {
+ HasNode(id uint32) bool
+}
+
+type balancer interface {
+ grpc.ClientConnInterface
+ nodeChecker
+}
+
+var _ query.Client = (*Client)(nil)
+
+type Client struct {
+ config *config.Config
+ grpcClient Ydb_Query_V1.QueryServiceClient
+ pool *pool.Pool[*Session, Session]
+
+ done chan struct{}
+}
+
+func (c *Client) Stats() *stats.Stats {
+ s := c.pool.Stats()
+
+ return &s
+}
+
+func (c *Client) Close(ctx context.Context) error {
+ close(c.done)
+
+ err := c.pool.Close(ctx)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+func do(
+ ctx context.Context,
+ pool *pool.Pool[*Session, Session],
+ op query.Operation,
+ t *trace.Query,
+ opts ...options.DoOption,
+) (attempts int, finalErr error) {
+ doOpts := options.ParseDoOpts(t, opts...)
+
+ err := pool.With(ctx, func(ctx context.Context, s *Session) error {
+ s.setStatus(statusInUse)
+
+ err := op(ctx, s)
+ if err != nil {
+ if !xerrors.IsRetryObjectValid(err) {
+ s.setStatus(statusError)
+ }
+
+ return xerrors.WithStackTrace(err)
+ }
+
+ s.setStatus(statusIdle)
+
+ return nil
+ }, append(doOpts.RetryOpts(), retry.WithTrace(&trace.Retry{
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
+ }
+ },
+ }))...)
+ if err != nil {
+ return attempts, xerrors.WithStackTrace(err)
+ }
+
+ return attempts, nil
+}
+
+func (c *Client) Do(ctx context.Context, op query.Operation, opts ...options.DoOption) error {
+ select {
+ case <-c.done:
+ return xerrors.WithStackTrace(errClosedClient)
+ default:
+ onDone := trace.QueryOnDo(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Client).Do"),
+ )
+ attempts, err := do(ctx, c.pool, op, c.config.Trace(), opts...)
+ onDone(attempts, err)
+
+ return err
+ }
+}
+
+func doTx(
+ ctx context.Context,
+ pool *pool.Pool[*Session, Session],
+ op query.TxOperation,
+ t *trace.Query,
+ opts ...options.DoTxOption,
+) (attempts int, err error) {
+ doTxOpts := options.ParseDoTxOpts(t, opts...)
+
+ attempts, err = do(ctx, pool, func(ctx context.Context, s query.Session) (err error) {
+ tx, err := s.Begin(ctx, doTxOpts.TxSettings())
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ err = op(ctx, tx)
+ if err != nil {
+ errRollback := tx.Rollback(ctx)
+ if errRollback != nil {
+ return xerrors.WithStackTrace(xerrors.Join(err, errRollback))
+ }
+
+ return xerrors.WithStackTrace(err)
+ }
+ err = tx.CommitTx(ctx)
+ if err != nil {
+ errRollback := tx.Rollback(ctx)
+ if errRollback != nil {
+ return xerrors.WithStackTrace(xerrors.Join(err, errRollback))
+ }
+
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+ }, t, doTxOpts.DoOpts()...)
+ if err != nil {
+ return attempts, xerrors.WithStackTrace(err)
+ }
+
+ return attempts, nil
+}
+
+func (c *Client) DoTx(ctx context.Context, op query.TxOperation, opts ...options.DoTxOption) (err error) {
+ select {
+ case <-c.done:
+ return xerrors.WithStackTrace(errClosedClient)
+ default:
+ onDone := trace.QueryOnDoTx(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Client).DoTx"),
+ )
+ attempts, err := doTx(ctx, c.pool, op, c.config.Trace(), opts...)
+ onDone(attempts, err)
+
+ return err
+ }
+}
+
+func New(ctx context.Context, balancer balancer, cfg *config.Config) *Client {
+ onDone := trace.QueryOnNew(cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.New"),
+ )
+ defer onDone()
+
+ client := &Client{
+ config: cfg,
+ grpcClient: Ydb_Query_V1.NewQueryServiceClient(balancer),
+ done: make(chan struct{}),
+ }
+
+ client.pool = pool.New(ctx,
+ pool.WithLimit[*Session, Session](cfg.PoolLimit()),
+ pool.WithTrace[*Session, Session](poolTrace(cfg.Trace())),
+ pool.WithCreateItemTimeout[*Session, Session](cfg.SessionCreateTimeout()),
+ pool.WithCloseItemTimeout[*Session, Session](cfg.SessionDeleteTimeout()),
+ pool.WithCreateFunc(func(ctx context.Context) (_ *Session, err error) {
+ var (
+ createCtx context.Context
+ cancelCreate context.CancelFunc
+ )
+ if d := cfg.SessionCreateTimeout(); d > 0 {
+ createCtx, cancelCreate = xcontext.WithTimeout(ctx, d)
+ } else {
+ createCtx, cancelCreate = xcontext.WithCancel(ctx)
+ }
+ defer cancelCreate()
+
+ s, err := createSession(createCtx, client.grpcClient, cfg,
+ withSessionCheck(func(s *Session) bool {
+ return balancer.HasNode(uint32(s.nodeID))
+ }),
+ )
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return s, nil
+ }),
+ )
+
+ return client
+}
+
+func poolTrace(t *trace.Query) *pool.Trace {
+ return &pool.Trace{
+ OnNew: func(info *pool.NewStartInfo) func(*pool.NewDoneInfo) {
+ onDone := trace.QueryOnPoolNew(t, info.Context, info.Call)
+
+ return func(info *pool.NewDoneInfo) {
+ onDone(info.Limit)
+ }
+ },
+ OnClose: func(info *pool.CloseStartInfo) func(*pool.CloseDoneInfo) {
+ onDone := trace.QueryOnClose(t, info.Context, info.Call)
+
+ return func(info *pool.CloseDoneInfo) {
+ onDone(info.Error)
+ }
+ },
+ OnTry: func(info *pool.TryStartInfo) func(*pool.TryDoneInfo) {
+ onDone := trace.QueryOnPoolTry(t, info.Context, info.Call)
+
+ return func(info *pool.TryDoneInfo) {
+ onDone(info.Error)
+ }
+ },
+ OnWith: func(info *pool.WithStartInfo) func(*pool.WithDoneInfo) {
+ onDone := trace.QueryOnPoolWith(t, info.Context, info.Call)
+
+ return func(info *pool.WithDoneInfo) {
+ onDone(info.Error, info.Attempts)
+ }
+ },
+ OnPut: func(info *pool.PutStartInfo) func(*pool.PutDoneInfo) {
+ onDone := trace.QueryOnPoolPut(t, info.Context, info.Call)
+
+ return func(info *pool.PutDoneInfo) {
+ onDone(info.Error)
+ }
+ },
+ OnGet: func(info *pool.GetStartInfo) func(*pool.GetDoneInfo) {
+ onDone := trace.QueryOnPoolGet(t, info.Context, info.Call)
+
+ return func(info *pool.GetDoneInfo) {
+ onDone(info.Error)
+ }
+ },
+ OnChange: func(info pool.ChangeInfo) {
+ trace.QueryOnPoolChange(t, info.Limit, info.Index, info.Idle, info.InUse)
+ },
+ }
+}
diff --git a/internal/query/client_test.go b/internal/query/client_test.go
new file mode 100644
index 000000000..1b7260750
--- /dev/null
+++ b/internal/query/client_test.go
@@ -0,0 +1,258 @@
+package query
+
+import (
+ "context"
+ "errors"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "go.uber.org/mock/gomock"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+func TestCreateSession(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ attachStream := NewMockQueryService_AttachSessionClient(ctrl)
+ attachStream.EXPECT().Recv().Return(&Ydb_Query.SessionState{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil).AnyTimes()
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CreateSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ SessionId: "test",
+ }, nil)
+ service.EXPECT().AttachSession(gomock.Any(), gomock.Any()).Return(attachStream, nil)
+ service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.DeleteSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil)
+ attached := 0
+ s, err := createSession(ctx, service, config.New(config.WithTrace(
+ &trace.Query{
+ OnSessionAttach: func(info trace.QuerySessionAttachStartInfo) func(info trace.QuerySessionAttachDoneInfo) {
+ return func(info trace.QuerySessionAttachDoneInfo) {
+ if info.Error == nil {
+ attached++
+ }
+ }
+ },
+ OnSessionDelete: func(info trace.QuerySessionDeleteStartInfo) func(info trace.QuerySessionDeleteDoneInfo) {
+ attached--
+
+ return nil
+ },
+ },
+ )))
+ require.NoError(t, err)
+ require.EqualValues(t, "test", s.id)
+ require.EqualValues(t, 1, attached)
+ err = s.Close(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, attached)
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ t.Run("OnCall", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ _, err := createSession(ctx, service, config.New())
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("OnAttach", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CreateSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ SessionId: "test",
+ }, nil)
+ service.EXPECT().AttachSession(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ _, err := createSession(ctx, service, config.New())
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("OnRecv", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ attachStream := NewMockQueryService_AttachSessionClient(ctrl)
+ attachStream.EXPECT().Recv().Return(nil, grpcStatus.Error(grpcCodes.Unavailable, "")).AnyTimes()
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CreateSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ SessionId: "test",
+ }, nil)
+ service.EXPECT().AttachSession(gomock.Any(), gomock.Any()).Return(attachStream, nil)
+ service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.DeleteSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil)
+ _, err := createSession(ctx, service, config.New())
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ }, xtest.StopAfter(time.Second))
+ })
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ t.Run("OnCall", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ _, err := createSession(ctx, service, config.New())
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("OnRecv", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ attachStream := NewMockQueryService_AttachSessionClient(ctrl)
+ attachStream.EXPECT().Recv().Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CreateSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ SessionId: "test",
+ }, nil)
+ service.EXPECT().AttachSession(gomock.Any(), gomock.Any()).Return(attachStream, nil)
+ service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.DeleteSessionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil)
+ _, err := createSession(ctx, service, config.New())
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ }, xtest.StopAfter(time.Second))
+ })
+ })
+}
+
+func newTestSession(id string) *Session {
+ return &Session{
+ id: id,
+ statusCode: statusIdle,
+ cfg: config.New(),
+ }
+}
+
+func newTestSessionWithClient(id string, client Ydb_Query_V1.QueryServiceClient) *Session {
+ return &Session{
+ id: id,
+ grpcClient: client,
+ statusCode: statusIdle,
+ cfg: config.New(),
+ }
+}
+
+func testPool(
+ ctx context.Context,
+ createSession func(ctx context.Context) (*Session, error),
+) *pool.Pool[*Session, Session] {
+ return pool.New[*Session, Session](ctx,
+ pool.WithLimit[*Session, Session](1),
+ pool.WithCreateFunc(createSession),
+ )
+}
+
+func TestDo(t *testing.T) {
+ ctx := xtest.Context(t)
+ t.Run("HappyWay", func(t *testing.T) {
+ attempts, err := do(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
+ return newTestSession("123"), nil
+ }), func(ctx context.Context, s query.Session) error {
+ return nil
+ }, &trace.Query{})
+ require.NoError(t, err)
+ require.EqualValues(t, 1, attempts)
+ })
+ t.Run("RetryableError", func(t *testing.T) {
+ counter := 0
+ attempts, err := do(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
+ return newTestSession("123"), nil
+ }), func(ctx context.Context, s query.Session) error {
+ counter++
+ if counter < 10 {
+ return xerrors.Retryable(errors.New(""))
+ }
+
+ return nil
+ }, &trace.Query{})
+ require.NoError(t, err)
+ require.EqualValues(t, 10, attempts)
+ require.Equal(t, 10, counter)
+ })
+}
+
+func TestDoTx(t *testing.T) {
+ ctx := xtest.Context(t)
+ t.Run("HappyWay", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ client := NewMockQueryServiceClient(ctrl)
+ client.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.BeginTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil)
+ client.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CommitTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil)
+ attempts, err := doTx(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
+ return newTestSessionWithClient("123", client), nil
+ }), func(ctx context.Context, tx query.TxActor) error {
+ return nil
+ }, &trace.Query{})
+ require.NoError(t, err)
+ require.EqualValues(t, 1, attempts)
+ })
+ t.Run("RetryableError", func(t *testing.T) {
+ counter := 0
+ ctrl := gomock.NewController(t)
+ client := NewMockQueryServiceClient(ctrl)
+ client.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.BeginTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil).AnyTimes()
+ client.EXPECT().RollbackTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.RollbackTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil).AnyTimes()
+ client.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CommitTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil).AnyTimes()
+ attempts, err := doTx(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
+ return newTestSessionWithClient("123", client), nil
+ }), func(ctx context.Context, tx query.TxActor) error {
+ counter++
+ if counter < 10 {
+ return xerrors.Retryable(errors.New(""))
+ }
+
+ return nil
+ }, &trace.Query{})
+ require.NoError(t, err)
+ require.EqualValues(t, 10, attempts)
+ require.Equal(t, 10, counter)
+ })
+}
diff --git a/internal/query/config/config.go b/internal/query/config/config.go
new file mode 100644
index 000000000..7adb08242
--- /dev/null
+++ b/internal/query/config/config.go
@@ -0,0 +1,70 @@
+package config
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+const (
+ DefaultSessionDeleteTimeout = 500 * time.Millisecond
+ DefaultSessionCreateTimeout = 500 * time.Millisecond
+ DefaultPoolMaxSize = pool.DefaultLimit
+)
+
+type Config struct {
+ config.Common
+
+ poolLimit int
+
+ sessionCreateTimeout time.Duration
+ sessionDeleteTimeout time.Duration
+
+ trace *trace.Query
+}
+
+func New(opts ...Option) *Config {
+ c := defaults()
+ for _, opt := range opts {
+ if opt != nil {
+ opt(c)
+ }
+ }
+
+ return c
+}
+
+func defaults() *Config {
+ return &Config{
+ poolLimit: DefaultPoolMaxSize,
+ sessionCreateTimeout: DefaultSessionCreateTimeout,
+ sessionDeleteTimeout: DefaultSessionDeleteTimeout,
+ trace: &trace.Query{},
+ }
+}
+
+// Trace defines trace over table client calls
+func (c *Config) Trace() *trace.Query {
+ return c.trace
+}
+
+// PoolLimit is an upper bound of pooled sessions.
+// If PoolLimit is less than or equal to zero then the
+// DefaultPoolMaxSize variable is used as a pool limit.
+func (c *Config) PoolLimit() int {
+ return c.poolLimit
+}
+
+// SessionCreateTimeout limits maximum time spent on Create session request
+func (c *Config) SessionCreateTimeout() time.Duration {
+ return c.sessionCreateTimeout
+}
+
+// SessionDeleteTimeout limits maximum time spent on Delete request
+//
+// If SessionDeleteTimeout is less than or equal to zero then the DefaultSessionDeleteTimeout is used.
+func (c *Config) SessionDeleteTimeout() time.Duration {
+ return c.sessionDeleteTimeout
+}
diff --git a/internal/query/config/options.go b/internal/query/config/options.go
new file mode 100644
index 000000000..2b30c5be2
--- /dev/null
+++ b/internal/query/config/options.go
@@ -0,0 +1,57 @@
+package config
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+type Option func(*Config)
+
+// With applies common configuration params
+func With(config config.Common) Option {
+ return func(c *Config) {
+ c.Common = config
+ }
+}
+
+// WithTrace appends table trace to early defined traces
+func WithTrace(trace *trace.Query, opts ...trace.QueryComposeOption) Option {
+ return func(c *Config) {
+ c.trace = c.trace.Compose(trace, opts...)
+ }
+}
+
+// WithPoolLimit defines upper bound of pooled sessions.
+// If poolLimit is less than or equal to zero then the
+// DefaultPoolMaxSize variable is used as a poolLimit.
+func WithPoolLimit(size int) Option {
+ return func(c *Config) {
+ if size > 0 {
+ c.poolLimit = size
+ }
+ }
+}
+
+// WithSessionCreateTimeout limits maximum time spent on Create session request
+// If sessionCreateTimeout is less than or equal to zero then no used timeout on create session request
+func WithSessionCreateTimeout(createSessionTimeout time.Duration) Option {
+ return func(c *Config) {
+ if createSessionTimeout > 0 {
+ c.sessionCreateTimeout = createSessionTimeout
+ } else {
+ c.sessionCreateTimeout = 0
+ }
+ }
+}
+
+// WithSessionDeleteTimeout limits maximum time spent on Delete request
+// If sessionDeleteTimeout is less than or equal to zero then the DefaultSessionDeleteTimeout is used.
+func WithSessionDeleteTimeout(deleteTimeout time.Duration) Option {
+ return func(c *Config) {
+ if deleteTimeout > 0 {
+ c.sessionDeleteTimeout = deleteTimeout
+ }
+ }
+}
diff --git a/internal/query/errors.go b/internal/query/errors.go
new file mode 100644
index 000000000..923ef8ed8
--- /dev/null
+++ b/internal/query/errors.go
@@ -0,0 +1,13 @@
+package query
+
+import (
+ "errors"
+)
+
+var (
+ ErrNotImplemented = errors.New("not implemented yet")
+ errWrongNextResultSetIndex = errors.New("wrong result set index")
+ errClosedResult = errors.New("result closed early")
+ errClosedClient = errors.New("query client closed early")
+ errWrongResultSetIndex = errors.New("critical violation of the logic - wrong result set index")
+)
diff --git a/internal/query/execute_query.go b/internal/query/execute_query.go
new file mode 100644
index 000000000..bf2fef314
--- /dev/null
+++ b/internal/query/execute_query.go
@@ -0,0 +1,82 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "google.golang.org/grpc"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+)
+
+type executeConfig interface {
+ ExecMode() options.ExecMode
+ StatsMode() options.StatsMode
+ TxControl() *query.TransactionControl
+ Syntax() options.Syntax
+ Params() *params.Parameters
+ CallOptions() []grpc.CallOption
+}
+
+func executeQueryRequest(a *allocator.Allocator, sessionID, q string, cfg executeConfig) (
+ *Ydb_Query.ExecuteQueryRequest,
+ []grpc.CallOption,
+) {
+ request := a.QueryExecuteQueryRequest()
+
+ request.SessionId = sessionID
+ request.ExecMode = Ydb_Query.ExecMode(cfg.ExecMode())
+ request.TxControl = cfg.TxControl().ToYDB(a)
+ request.Query = queryFromText(a, q, Ydb_Query.Syntax(cfg.Syntax()))
+ request.Parameters = cfg.Params().ToYDB(a)
+ request.StatsMode = Ydb_Query.StatsMode(cfg.StatsMode())
+ request.ConcurrentResultSets = false
+
+ return request, cfg.CallOptions()
+}
+
+func queryFromText(
+ a *allocator.Allocator, q string, syntax Ydb_Query.Syntax,
+) *Ydb_Query.ExecuteQueryRequest_QueryContent {
+ content := a.QueryExecuteQueryRequestQueryContent()
+ content.QueryContent = a.QueryQueryContent()
+ content.QueryContent.Syntax = syntax
+ content.QueryContent.Text = q
+
+ return content
+}
+
+func execute(ctx context.Context, s *Session, c Ydb_Query_V1.QueryServiceClient, q string, cfg executeConfig) (
+ _ *transaction, _ *result, finalErr error,
+) {
+ a := allocator.New()
+ defer a.Free()
+
+ request, callOptions := executeQueryRequest(a, s.id, q, cfg)
+
+ executeCtx, cancelExecute := xcontext.WithCancel(xcontext.ValueOnly(ctx))
+
+ stream, err := c.ExecuteQuery(executeCtx, request, callOptions...)
+ if err != nil {
+ return nil, nil, xerrors.WithStackTrace(err)
+ }
+
+ r, txID, err := newResult(ctx, stream, s.cfg.Trace(), cancelExecute)
+ if err != nil {
+ cancelExecute()
+
+ return nil, nil, xerrors.WithStackTrace(err)
+ }
+
+ if txID == "" {
+ return nil, r, nil
+ }
+
+ return newTransaction(txID, s), r, nil
+}
diff --git a/internal/query/execute_query_test.go b/internal/query/execute_query_test.go
new file mode 100644
index 000000000..4089a5465
--- /dev/null
+++ b/internal/query/execute_query_test.go
@@ -0,0 +1,1073 @@
+package query
+
+import (
+ "context"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "go.uber.org/mock/gomock"
+ "google.golang.org/grpc"
+ grpcCodes "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+ grpcStatus "google.golang.org/grpc/status"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestExecute(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ TxMeta: &Ydb_Query.TransactionMeta{
+ Id: "456",
+ },
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 1,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "d",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "e",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 1,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 2,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "d",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "e",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 2,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, io.EOF)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
+ tx, r, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
+ require.NoError(t, err)
+ defer r.Close(ctx)
+ require.EqualValues(t, "456", tx.id)
+ require.EqualValues(t, "123", tx.s.id)
+ require.EqualValues(t, -1, r.resultSetIndex)
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=5)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=6)")
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ }
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.index)
+ }
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=5)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=6)")
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ }
+ {
+ t.Log("close result")
+ r.Close(context.Background())
+ }
+ {
+ t.Log("nextResultSet")
+ _, err := r.nextResultSet(context.Background())
+ require.ErrorIs(t, err, errClosedResult)
+ }
+ t.Log("check final error")
+ require.NoError(t, r.Err())
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ t.Run("OnCall", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ t.Log("execute")
+ _, _, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ })
+ t.Run("OnStream", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ TxMeta: &Ydb_Query.TransactionMeta{
+ Id: "456",
+ },
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
+ t.Log("execute")
+ tx, r, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
+ require.NoError(t, err)
+ defer r.Close(ctx)
+ require.EqualValues(t, "456", tx.id)
+ require.EqualValues(t, "123", tx.s.id)
+ require.EqualValues(t, -1, r.resultSetIndex)
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=5)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=6)")
+ _, err := rs.nextRow(ctx)
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ }
+ }
+ t.Log("check final error")
+ require.Error(t, r.Err())
+ require.True(t, xerrors.IsTransportError(r.Err(), grpcCodes.Unavailable))
+ })
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ t.Run("OnCall", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(nil, xerrors.Operation(xerrors.WithStatusCode(
+ Ydb.StatusIds_UNAVAILABLE,
+ )))
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
+ t.Log("execute")
+ _, _, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ })
+ t.Run("OnStream", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ TxMeta: &Ydb_Query.TransactionMeta{
+ Id: "456",
+ },
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, xerrors.Operation(xerrors.WithStatusCode(
+ Ydb.StatusIds_UNAVAILABLE,
+ )))
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
+ t.Log("execute")
+ tx, r, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
+ require.NoError(t, err)
+ defer r.Close(ctx)
+ require.EqualValues(t, "456", tx.id)
+ require.EqualValues(t, "123", tx.s.id)
+ require.EqualValues(t, -1, r.resultSetIndex)
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ }
+ }
+ t.Log("check final error")
+ require.Error(t, r.Err())
+ require.True(t, xerrors.IsOperationError(r.Err(), Ydb.StatusIds_UNAVAILABLE))
+ })
+ })
+}
+
+func TestExecuteQueryRequest(t *testing.T) {
+ a := allocator.New()
+ for _, tt := range []struct {
+ name string
+ opts []options.ExecuteOption
+ request *Ydb_Query.ExecuteQueryRequest
+ callOptions []grpc.CallOption
+ }{
+ {
+ name: "WithoutOptions",
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithoutOptions",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithoutOptions",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithParams",
+ opts: []options.ExecuteOption{
+ options.WithParameters(
+ params.Builder{}.
+ Param("$a").Text("A").
+ Param("$b").Text("B").
+ Param("$c").Text("C").
+ Build(),
+ ),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithParams",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithParams",
+ },
+ },
+ Parameters: map[string]*Ydb.TypedValue{
+ "$a": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "A",
+ },
+ },
+ },
+ "$b": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "B",
+ },
+ },
+ },
+ "$c": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "C",
+ },
+ },
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithExplain",
+ opts: []options.ExecuteOption{
+ options.WithExecMode(options.ExecModeExplain),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithExplain",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXPLAIN,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithExplain",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithValidate",
+ opts: []options.ExecuteOption{
+ options.WithExecMode(options.ExecModeValidate),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithValidate",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_VALIDATE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithValidate",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithValidate",
+ opts: []options.ExecuteOption{
+ options.WithExecMode(options.ExecModeParse),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithValidate",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_PARSE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithValidate",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithStatsFull",
+ opts: []options.ExecuteOption{
+ options.WithStatsMode(options.StatsModeFull),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithStatsFull",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithStatsFull",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_FULL,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithStatsBasic",
+ opts: []options.ExecuteOption{
+ options.WithStatsMode(options.StatsModeBasic),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithStatsBasic",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithStatsBasic",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_BASIC,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithStatsProfile",
+ opts: []options.ExecuteOption{
+ options.WithStatsMode(options.StatsModeProfile),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithStatsProfile",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithStatsProfile",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_PROFILE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithGrpcCallOptions",
+ opts: []options.ExecuteOption{
+ options.WithCallOptions(grpc.Header(&metadata.MD{
+ "ext-header": []string{"test"},
+ })),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithGrpcCallOptions",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ TxControl: &Ydb_Query.TransactionControl{
+ TxSelector: &Ydb_Query.TransactionControl_BeginTx{
+ BeginTx: &Ydb_Query.TransactionSettings{
+ TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ },
+ },
+ },
+ CommitTx: true,
+ },
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithGrpcCallOptions",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ callOptions: []grpc.CallOption{
+ grpc.Header(&metadata.MD{
+ "ext-header": []string{"test"},
+ }),
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ request, callOptions := executeQueryRequest(a, tt.name, tt.name, options.ExecuteSettings(tt.opts...))
+ require.Equal(t, request.String(), tt.request.String())
+ require.Equal(t, tt.callOptions, callOptions)
+ })
+ }
+}
diff --git a/internal/query/grpc_client_mock_test.go b/internal/query/grpc_client_mock_test.go
new file mode 100644
index 000000000..d81f0cfab
--- /dev/null
+++ b/internal/query/grpc_client_mock_test.go
@@ -0,0 +1,468 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1 (interfaces: QueryServiceClient,QueryService_AttachSessionClient,QueryService_ExecuteQueryClient)
+//
+// Generated by this command:
+//
+// mockgen -destination grpc_client_mock_test.go -package query -write_package_comment=false github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1 QueryServiceClient,QueryService_AttachSessionClient,QueryService_ExecuteQueryClient
+package query
+
+import (
+ context "context"
+ reflect "reflect"
+
+ Ydb_Query_V1 "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ Ydb_Operations "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations"
+ Ydb_Query "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ gomock "go.uber.org/mock/gomock"
+ grpc "google.golang.org/grpc"
+ metadata "google.golang.org/grpc/metadata"
+)
+
+// MockQueryServiceClient is a mock of QueryServiceClient interface.
+type MockQueryServiceClient struct {
+ ctrl *gomock.Controller
+ recorder *MockQueryServiceClientMockRecorder
+}
+
+// MockQueryServiceClientMockRecorder is the mock recorder for MockQueryServiceClient.
+type MockQueryServiceClientMockRecorder struct {
+ mock *MockQueryServiceClient
+}
+
+// NewMockQueryServiceClient creates a new mock instance.
+func NewMockQueryServiceClient(ctrl *gomock.Controller) *MockQueryServiceClient {
+ mock := &MockQueryServiceClient{ctrl: ctrl}
+ mock.recorder = &MockQueryServiceClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockQueryServiceClient) EXPECT() *MockQueryServiceClientMockRecorder {
+ return m.recorder
+}
+
+// AttachSession mocks base method.
+func (m *MockQueryServiceClient) AttachSession(arg0 context.Context, arg1 *Ydb_Query.AttachSessionRequest, arg2 ...grpc.CallOption) (Ydb_Query_V1.QueryService_AttachSessionClient, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "AttachSession", varargs...)
+ ret0, _ := ret[0].(Ydb_Query_V1.QueryService_AttachSessionClient)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// AttachSession indicates an expected call of AttachSession.
+func (mr *MockQueryServiceClientMockRecorder) AttachSession(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AttachSession", reflect.TypeOf((*MockQueryServiceClient)(nil).AttachSession), varargs...)
+}
+
+// BeginTransaction mocks base method.
+func (m *MockQueryServiceClient) BeginTransaction(arg0 context.Context, arg1 *Ydb_Query.BeginTransactionRequest, arg2 ...grpc.CallOption) (*Ydb_Query.BeginTransactionResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "BeginTransaction", varargs...)
+ ret0, _ := ret[0].(*Ydb_Query.BeginTransactionResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// BeginTransaction indicates an expected call of BeginTransaction.
+func (mr *MockQueryServiceClientMockRecorder) BeginTransaction(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginTransaction", reflect.TypeOf((*MockQueryServiceClient)(nil).BeginTransaction), varargs...)
+}
+
+// CommitTransaction mocks base method.
+func (m *MockQueryServiceClient) CommitTransaction(arg0 context.Context, arg1 *Ydb_Query.CommitTransactionRequest, arg2 ...grpc.CallOption) (*Ydb_Query.CommitTransactionResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "CommitTransaction", varargs...)
+ ret0, _ := ret[0].(*Ydb_Query.CommitTransactionResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// CommitTransaction indicates an expected call of CommitTransaction.
+func (mr *MockQueryServiceClientMockRecorder) CommitTransaction(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitTransaction", reflect.TypeOf((*MockQueryServiceClient)(nil).CommitTransaction), varargs...)
+}
+
+// CreateSession mocks base method.
+func (m *MockQueryServiceClient) CreateSession(arg0 context.Context, arg1 *Ydb_Query.CreateSessionRequest, arg2 ...grpc.CallOption) (*Ydb_Query.CreateSessionResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "CreateSession", varargs...)
+ ret0, _ := ret[0].(*Ydb_Query.CreateSessionResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// CreateSession indicates an expected call of CreateSession.
+func (mr *MockQueryServiceClientMockRecorder) CreateSession(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSession", reflect.TypeOf((*MockQueryServiceClient)(nil).CreateSession), varargs...)
+}
+
+// DeleteSession mocks base method.
+func (m *MockQueryServiceClient) DeleteSession(arg0 context.Context, arg1 *Ydb_Query.DeleteSessionRequest, arg2 ...grpc.CallOption) (*Ydb_Query.DeleteSessionResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "DeleteSession", varargs...)
+ ret0, _ := ret[0].(*Ydb_Query.DeleteSessionResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// DeleteSession indicates an expected call of DeleteSession.
+func (mr *MockQueryServiceClientMockRecorder) DeleteSession(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSession", reflect.TypeOf((*MockQueryServiceClient)(nil).DeleteSession), varargs...)
+}
+
+// ExecuteQuery mocks base method.
+func (m *MockQueryServiceClient) ExecuteQuery(arg0 context.Context, arg1 *Ydb_Query.ExecuteQueryRequest, arg2 ...grpc.CallOption) (Ydb_Query_V1.QueryService_ExecuteQueryClient, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "ExecuteQuery", varargs...)
+ ret0, _ := ret[0].(Ydb_Query_V1.QueryService_ExecuteQueryClient)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// ExecuteQuery indicates an expected call of ExecuteQuery.
+func (mr *MockQueryServiceClientMockRecorder) ExecuteQuery(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteQuery", reflect.TypeOf((*MockQueryServiceClient)(nil).ExecuteQuery), varargs...)
+}
+
+// ExecuteScript mocks base method.
+func (m *MockQueryServiceClient) ExecuteScript(arg0 context.Context, arg1 *Ydb_Query.ExecuteScriptRequest, arg2 ...grpc.CallOption) (*Ydb_Operations.Operation, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "ExecuteScript", varargs...)
+ ret0, _ := ret[0].(*Ydb_Operations.Operation)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// ExecuteScript indicates an expected call of ExecuteScript.
+func (mr *MockQueryServiceClientMockRecorder) ExecuteScript(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteScript", reflect.TypeOf((*MockQueryServiceClient)(nil).ExecuteScript), varargs...)
+}
+
+// FetchScriptResults mocks base method.
+func (m *MockQueryServiceClient) FetchScriptResults(arg0 context.Context, arg1 *Ydb_Query.FetchScriptResultsRequest, arg2 ...grpc.CallOption) (*Ydb_Query.FetchScriptResultsResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "FetchScriptResults", varargs...)
+ ret0, _ := ret[0].(*Ydb_Query.FetchScriptResultsResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// FetchScriptResults indicates an expected call of FetchScriptResults.
+func (mr *MockQueryServiceClientMockRecorder) FetchScriptResults(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchScriptResults", reflect.TypeOf((*MockQueryServiceClient)(nil).FetchScriptResults), varargs...)
+}
+
+// RollbackTransaction mocks base method.
+func (m *MockQueryServiceClient) RollbackTransaction(arg0 context.Context, arg1 *Ydb_Query.RollbackTransactionRequest, arg2 ...grpc.CallOption) (*Ydb_Query.RollbackTransactionResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "RollbackTransaction", varargs...)
+ ret0, _ := ret[0].(*Ydb_Query.RollbackTransactionResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// RollbackTransaction indicates an expected call of RollbackTransaction.
+func (mr *MockQueryServiceClientMockRecorder) RollbackTransaction(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackTransaction", reflect.TypeOf((*MockQueryServiceClient)(nil).RollbackTransaction), varargs...)
+}
+
+// MockQueryService_AttachSessionClient is a mock of QueryService_AttachSessionClient interface.
+type MockQueryService_AttachSessionClient struct {
+ ctrl *gomock.Controller
+ recorder *MockQueryService_AttachSessionClientMockRecorder
+}
+
+// MockQueryService_AttachSessionClientMockRecorder is the mock recorder for MockQueryService_AttachSessionClient.
+type MockQueryService_AttachSessionClientMockRecorder struct {
+ mock *MockQueryService_AttachSessionClient
+}
+
+// NewMockQueryService_AttachSessionClient creates a new mock instance.
+func NewMockQueryService_AttachSessionClient(ctrl *gomock.Controller) *MockQueryService_AttachSessionClient {
+ mock := &MockQueryService_AttachSessionClient{ctrl: ctrl}
+ mock.recorder = &MockQueryService_AttachSessionClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockQueryService_AttachSessionClient) EXPECT() *MockQueryService_AttachSessionClientMockRecorder {
+ return m.recorder
+}
+
+// CloseSend mocks base method.
+func (m *MockQueryService_AttachSessionClient) CloseSend() error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "CloseSend")
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// CloseSend indicates an expected call of CloseSend.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) CloseSend() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).CloseSend))
+}
+
+// Context mocks base method.
+func (m *MockQueryService_AttachSessionClient) Context() context.Context {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Context")
+ ret0, _ := ret[0].(context.Context)
+ return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) Context() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).Context))
+}
+
+// Header mocks base method.
+func (m *MockQueryService_AttachSessionClient) Header() (metadata.MD, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Header")
+ ret0, _ := ret[0].(metadata.MD)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Header indicates an expected call of Header.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) Header() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).Header))
+}
+
+// Recv mocks base method.
+func (m *MockQueryService_AttachSessionClient) Recv() (*Ydb_Query.SessionState, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Recv")
+ ret0, _ := ret[0].(*Ydb_Query.SessionState)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Recv indicates an expected call of Recv.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) Recv() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).Recv))
+}
+
+// RecvMsg mocks base method.
+func (m *MockQueryService_AttachSessionClient) RecvMsg(arg0 any) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "RecvMsg", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) RecvMsg(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).RecvMsg), arg0)
+}
+
+// SendMsg mocks base method.
+func (m *MockQueryService_AttachSessionClient) SendMsg(arg0 any) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SendMsg", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) SendMsg(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).SendMsg), arg0)
+}
+
+// Trailer mocks base method.
+func (m *MockQueryService_AttachSessionClient) Trailer() metadata.MD {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Trailer")
+ ret0, _ := ret[0].(metadata.MD)
+ return ret0
+}
+
+// Trailer indicates an expected call of Trailer.
+func (mr *MockQueryService_AttachSessionClientMockRecorder) Trailer() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockQueryService_AttachSessionClient)(nil).Trailer))
+}
+
+// MockQueryService_ExecuteQueryClient is a mock of QueryService_ExecuteQueryClient interface.
+type MockQueryService_ExecuteQueryClient struct {
+ ctrl *gomock.Controller
+ recorder *MockQueryService_ExecuteQueryClientMockRecorder
+}
+
+// MockQueryService_ExecuteQueryClientMockRecorder is the mock recorder for MockQueryService_ExecuteQueryClient.
+type MockQueryService_ExecuteQueryClientMockRecorder struct {
+ mock *MockQueryService_ExecuteQueryClient
+}
+
+// NewMockQueryService_ExecuteQueryClient creates a new mock instance.
+func NewMockQueryService_ExecuteQueryClient(ctrl *gomock.Controller) *MockQueryService_ExecuteQueryClient {
+ mock := &MockQueryService_ExecuteQueryClient{ctrl: ctrl}
+ mock.recorder = &MockQueryService_ExecuteQueryClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockQueryService_ExecuteQueryClient) EXPECT() *MockQueryService_ExecuteQueryClientMockRecorder {
+ return m.recorder
+}
+
+// CloseSend mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) CloseSend() error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "CloseSend")
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// CloseSend indicates an expected call of CloseSend.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) CloseSend() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).CloseSend))
+}
+
+// Context mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) Context() context.Context {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Context")
+ ret0, _ := ret[0].(context.Context)
+ return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) Context() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).Context))
+}
+
+// Header mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) Header() (metadata.MD, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Header")
+ ret0, _ := ret[0].(metadata.MD)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Header indicates an expected call of Header.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) Header() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).Header))
+}
+
+// Recv mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) Recv() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Recv")
+ ret0, _ := ret[0].(*Ydb_Query.ExecuteQueryResponsePart)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Recv indicates an expected call of Recv.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) Recv() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).Recv))
+}
+
+// RecvMsg mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) RecvMsg(arg0 any) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "RecvMsg", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) RecvMsg(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).RecvMsg), arg0)
+}
+
+// SendMsg mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) SendMsg(arg0 any) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SendMsg", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) SendMsg(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).SendMsg), arg0)
+}
+
+// Trailer mocks base method.
+func (m *MockQueryService_ExecuteQueryClient) Trailer() metadata.MD {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Trailer")
+ ret0, _ := ret[0].(metadata.MD)
+ return ret0
+}
+
+// Trailer indicates an expected call of Trailer.
+func (mr *MockQueryService_ExecuteQueryClientMockRecorder) Trailer() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockQueryService_ExecuteQueryClient)(nil).Trailer))
+}
diff --git a/internal/query/options/execute.go b/internal/query/options/execute.go
new file mode 100644
index 000000000..6a306c26d
--- /dev/null
+++ b/internal/query/options/execute.go
@@ -0,0 +1,224 @@
+package options
+
+import (
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "google.golang.org/grpc"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/tx"
+)
+
+type (
+ Syntax Ydb_Query.Syntax
+ ExecMode Ydb_Query.ExecMode
+ StatsMode Ydb_Query.StatsMode
+ CallOptions []grpc.CallOption
+ commonExecuteSettings struct {
+ syntax Syntax
+ params params.Parameters
+ execMode ExecMode
+ statsMode StatsMode
+ callOptions []grpc.CallOption
+ }
+ Execute struct {
+ commonExecuteSettings
+
+ txControl *tx.Control
+ }
+ ExecuteOption interface {
+ applyExecuteOption(s *Execute)
+ }
+ txExecuteSettings struct {
+ ExecuteSettings *Execute
+
+ commitTx bool
+ }
+ TxExecuteOption interface {
+ applyTxExecuteOption(s *txExecuteSettings)
+ }
+ txCommitOption struct{}
+ ParametersOption params.Parameters
+ TxControlOption struct {
+ txControl *tx.Control
+ }
+)
+
+func (opt TxControlOption) applyExecuteOption(s *Execute) {
+ s.txControl = opt.txControl
+}
+
+func (t txCommitOption) applyTxExecuteOption(s *txExecuteSettings) {
+ s.commitTx = true
+}
+
+func (syntax Syntax) applyTxExecuteOption(s *txExecuteSettings) {
+ syntax.applyExecuteOption(s.ExecuteSettings)
+}
+
+func (syntax Syntax) applyExecuteOption(s *Execute) {
+ s.syntax = syntax
+}
+
+const (
+ SyntaxYQL = Syntax(Ydb_Query.Syntax_SYNTAX_YQL_V1)
+ SyntaxPostgreSQL = Syntax(Ydb_Query.Syntax_SYNTAX_PG)
+)
+
+func (params ParametersOption) applyTxExecuteOption(s *txExecuteSettings) {
+ params.applyExecuteOption(s.ExecuteSettings)
+}
+
+func (params ParametersOption) applyExecuteOption(s *Execute) {
+ s.params = append(s.params, params...)
+}
+
+func (opts CallOptions) applyExecuteOption(s *Execute) {
+ s.callOptions = append(s.callOptions, opts...)
+}
+
+func (opts CallOptions) applyTxExecuteOption(s *txExecuteSettings) {
+ opts.applyExecuteOption(s.ExecuteSettings)
+}
+
+func (mode StatsMode) applyTxExecuteOption(s *txExecuteSettings) {
+ mode.applyExecuteOption(s.ExecuteSettings)
+}
+
+func (mode StatsMode) applyExecuteOption(s *Execute) {
+ s.statsMode = mode
+}
+
+func (mode ExecMode) applyTxExecuteOption(s *txExecuteSettings) {
+ mode.applyExecuteOption(s.ExecuteSettings)
+}
+
+func (mode ExecMode) applyExecuteOption(s *Execute) {
+ s.execMode = mode
+}
+
+const (
+ ExecModeParse = ExecMode(Ydb_Query.ExecMode_EXEC_MODE_PARSE)
+ ExecModeValidate = ExecMode(Ydb_Query.ExecMode_EXEC_MODE_VALIDATE)
+ ExecModeExplain = ExecMode(Ydb_Query.ExecMode_EXEC_MODE_EXPLAIN)
+ ExecModeExecute = ExecMode(Ydb_Query.ExecMode_EXEC_MODE_EXECUTE)
+)
+
+const (
+ StatsModeBasic = StatsMode(Ydb_Query.StatsMode_STATS_MODE_BASIC)
+ StatsModeNone = StatsMode(Ydb_Query.StatsMode_STATS_MODE_NONE)
+ StatsModeFull = StatsMode(Ydb_Query.StatsMode_STATS_MODE_FULL)
+ StatsModeProfile = StatsMode(Ydb_Query.StatsMode_STATS_MODE_PROFILE)
+)
+
+func defaultCommonExecuteSettings() commonExecuteSettings {
+ return commonExecuteSettings{
+ syntax: SyntaxYQL,
+ execMode: ExecModeExecute,
+ statsMode: StatsModeNone,
+ }
+}
+
+func ExecuteSettings(opts ...ExecuteOption) (settings *Execute) {
+ settings = &Execute{
+ commonExecuteSettings: defaultCommonExecuteSettings(),
+ }
+ settings.commonExecuteSettings = defaultCommonExecuteSettings()
+ settings.txControl = tx.DefaultTxControl()
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyExecuteOption(settings)
+ }
+ }
+
+ return settings
+}
+
+func (s *Execute) TxControl() *tx.Control {
+ return s.txControl
+}
+
+func (s *Execute) SetTxControl(ctrl *tx.Control) {
+ s.txControl = ctrl
+}
+
+func (s *commonExecuteSettings) CallOptions() []grpc.CallOption {
+ return s.callOptions
+}
+
+func (s *commonExecuteSettings) Syntax() Syntax {
+ return s.syntax
+}
+
+func (s *commonExecuteSettings) ExecMode() ExecMode {
+ return s.execMode
+}
+
+func (s *commonExecuteSettings) StatsMode() StatsMode {
+ return s.statsMode
+}
+
+func (s *commonExecuteSettings) Params() *params.Parameters {
+ if len(s.params) == 0 {
+ return nil
+ }
+
+ return &s.params
+}
+
+func TxExecuteSettings(id string, opts ...TxExecuteOption) (settings *txExecuteSettings) {
+ settings = &txExecuteSettings{
+ ExecuteSettings: ExecuteSettings(WithTxControl(tx.NewControl(tx.WithTxID(id)))),
+ }
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyTxExecuteOption(settings)
+ }
+ }
+
+ return settings
+}
+
+var _ ExecuteOption = ParametersOption{}
+
+func WithParameters(parameters *params.Parameters) ParametersOption {
+ return ParametersOption(*parameters)
+}
+
+var (
+ _ ExecuteOption = ExecMode(0)
+ _ ExecuteOption = StatsMode(0)
+ _ TxExecuteOption = ExecMode(0)
+ _ TxExecuteOption = StatsMode(0)
+ _ TxExecuteOption = txCommitOption{}
+ _ ExecuteOption = TxControlOption{}
+)
+
+func WithCommit() txCommitOption {
+ return txCommitOption{}
+}
+
+type ExecModeOption = ExecMode
+
+func WithExecMode(mode ExecMode) ExecMode {
+ return mode
+}
+
+type SyntaxOption = Syntax
+
+func WithSyntax(syntax Syntax) SyntaxOption {
+ return syntax
+}
+
+type StatsModeOption = StatsMode
+
+func WithStatsMode(mode StatsMode) StatsMode {
+ return mode
+}
+
+func WithCallOptions(opts ...grpc.CallOption) CallOptions {
+ return opts
+}
+
+func WithTxControl(txControl *tx.Control) TxControlOption {
+ return TxControlOption{txControl}
+}
diff --git a/internal/query/options/retry.go b/internal/query/options/retry.go
new file mode 100644
index 000000000..b604152e3
--- /dev/null
+++ b/internal/query/options/retry.go
@@ -0,0 +1,138 @@
+package options
+
+import (
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/tx"
+ "github.com/ydb-platform/ydb-go-sdk/v3/retry"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+var (
+ _ DoOption = idempotentOption{}
+ _ DoOption = labelOption("")
+ _ DoOption = traceOption{}
+
+ _ DoTxOption = idempotentOption{}
+ _ DoTxOption = labelOption("")
+ _ DoTxOption = traceOption{}
+ _ DoTxOption = doTxSettingsOption{}
+)
+
+type (
+ DoOption interface {
+ applyDoOption(s *doSettings)
+ }
+
+ doSettings struct {
+ retryOpts []retry.Option
+ trace *trace.Query
+ }
+
+ DoTxOption interface {
+ applyDoTxOption(o *doTxSettings)
+ }
+
+ doTxSettings struct {
+ doOpts []DoOption
+ txSettings tx.Settings
+ }
+
+ idempotentOption struct{}
+ labelOption string
+ traceOption struct {
+ t *trace.Query
+ }
+ doTxSettingsOption struct {
+ txSettings tx.Settings
+ }
+)
+
+func (s *doSettings) Trace() *trace.Query {
+ return s.trace
+}
+
+func (s *doSettings) RetryOpts() []retry.Option {
+ return s.retryOpts
+}
+
+func (s *doTxSettings) DoOpts() []DoOption {
+ return s.doOpts
+}
+
+func (s *doTxSettings) TxSettings() tx.Settings {
+ return s.txSettings
+}
+
+func (opt idempotentOption) applyDoTxOption(s *doTxSettings) {
+ s.doOpts = append(s.doOpts, opt)
+}
+
+func (idempotentOption) applyDoOption(s *doSettings) {
+ s.retryOpts = append(s.retryOpts, retry.WithIdempotent(true))
+}
+
+func (opt traceOption) applyDoOption(s *doSettings) {
+ s.trace = s.trace.Compose(opt.t)
+}
+
+func (opt traceOption) applyDoTxOption(s *doTxSettings) {
+ s.doOpts = append(s.doOpts, opt)
+}
+
+func (opt labelOption) applyDoOption(s *doSettings) {
+ s.retryOpts = append(s.retryOpts, retry.WithLabel(string(opt)))
+}
+
+func (opt labelOption) applyDoTxOption(s *doTxSettings) {
+ s.doOpts = append(s.doOpts, opt)
+}
+
+func (opt doTxSettingsOption) applyDoTxOption(opts *doTxSettings) {
+ opts.txSettings = opt.txSettings
+}
+
+func WithTxSettings(txSettings tx.Settings) doTxSettingsOption {
+ return doTxSettingsOption{txSettings: txSettings}
+}
+
+func WithIdempotent() idempotentOption {
+ return idempotentOption{}
+}
+
+func WithLabel(lbl string) labelOption {
+ return labelOption(lbl)
+}
+
+func WithTrace(t *trace.Query) traceOption {
+ return traceOption{t: t}
+}
+
+func ParseDoOpts(t *trace.Query, opts ...DoOption) (s *doSettings) {
+ s = &doSettings{
+ trace: t,
+ }
+
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyDoOption(s)
+ }
+ }
+
+ return s
+}
+
+func ParseDoTxOpts(t *trace.Query, opts ...DoTxOption) (s *doTxSettings) {
+ s = &doTxSettings{
+ txSettings: tx.NewSettings(tx.WithDefaultTxMode()),
+ doOpts: []DoOption{
+ WithTrace(t),
+ },
+ }
+
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyDoTxOption(s)
+ }
+ }
+
+ return s
+}
diff --git a/internal/query/result.go b/internal/query/result.go
new file mode 100644
index 000000000..78478610d
--- /dev/null
+++ b/internal/query/result.go
@@ -0,0 +1,204 @@
+package query
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+var _ query.Result = (*result)(nil)
+
+type result struct {
+ stream Ydb_Query_V1.QueryService_ExecuteQueryClient
+ closeOnce func(ctx context.Context) error
+ lastPart *Ydb_Query.ExecuteQueryResponsePart
+ resultSetIndex int64
+ errs []error
+ closed chan struct{}
+ trace *trace.Query
+}
+
+func newResult(
+ ctx context.Context,
+ stream Ydb_Query_V1.QueryService_ExecuteQueryClient,
+ t *trace.Query,
+ closeResult context.CancelFunc,
+) (_ *result, txID string, err error) {
+ if t == nil {
+ t = &trace.Query{}
+ }
+ if closeResult == nil {
+ closeResult = func() {}
+ }
+
+ onDone := trace.QueryOnResultNew(t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.newResult"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ select {
+ case <-ctx.Done():
+ return nil, txID, xerrors.WithStackTrace(ctx.Err())
+ default:
+ part, err := nextPart(ctx, stream, t)
+ if err != nil {
+ return nil, txID, xerrors.WithStackTrace(err)
+ }
+ var (
+ interrupted = make(chan struct{})
+ closed = make(chan struct{})
+ closeOnce = xsync.OnceFunc(func(ctx context.Context) error {
+ closeResult()
+
+ close(interrupted)
+ close(closed)
+
+ return nil
+ })
+ )
+
+ return &result{
+ stream: stream,
+ resultSetIndex: -1,
+ lastPart: part,
+ closed: closed,
+ closeOnce: closeOnce,
+ trace: t,
+ }, part.GetTxMeta().GetId(), nil
+ }
+}
+
+func nextPart(
+ ctx context.Context,
+ stream Ydb_Query_V1.QueryService_ExecuteQueryClient,
+ t *trace.Query,
+) (_ *Ydb_Query.ExecuteQueryResponsePart, finalErr error) {
+ if t == nil {
+ t = &trace.Query{}
+ }
+
+ onDone := trace.QueryOnResultNextPart(t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.nextPart"),
+ )
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ part, err := stream.Recv()
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+}
+
+func (r *result) Close(ctx context.Context) (err error) {
+ onDone := trace.QueryOnResultClose(r.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*result).Close"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ return r.closeOnce(ctx)
+}
+
+func (r *result) nextResultSet(ctx context.Context) (_ *resultSet, err error) {
+ defer func() {
+ if err != nil && !xerrors.Is(err,
+ io.EOF, errClosedResult, context.Canceled,
+ ) {
+ r.errs = append(r.errs, err)
+ }
+ }()
+ nextResultSetIndex := r.resultSetIndex + 1
+ for {
+ select {
+ case <-r.closed:
+ return nil, xerrors.WithStackTrace(errClosedResult)
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ default:
+ if resultSetIndex := r.lastPart.GetResultSetIndex(); resultSetIndex >= nextResultSetIndex { //nolint:nestif
+ r.resultSetIndex = resultSetIndex
+
+ return newResultSet(func() (_ *Ydb_Query.ExecuteQueryResponsePart, err error) {
+ defer func() {
+ if err != nil && !xerrors.Is(err,
+ io.EOF, context.Canceled,
+ ) {
+ r.errs = append(r.errs, err)
+ }
+ }()
+ select {
+ case <-r.closed:
+ return nil, errClosedResult
+ default:
+ part, err := nextPart(ctx, r.stream, r.trace)
+ if err != nil {
+ if xerrors.Is(err, io.EOF) {
+ _ = r.closeOnce(ctx)
+ }
+
+ return nil, xerrors.WithStackTrace(err)
+ }
+ r.lastPart = part
+ if part.GetResultSetIndex() > nextResultSetIndex {
+ return nil, xerrors.WithStackTrace(fmt.Errorf(
+ "result set (index=%d) receive part (index=%d) for next result set: %w",
+ nextResultSetIndex, part.GetResultSetIndex(), io.EOF,
+ ))
+ }
+
+ return part, nil
+ }
+ }, r.lastPart, r.trace), nil
+ }
+ part, err := nextPart(ctx, r.stream, r.trace)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+ if part.GetResultSetIndex() < r.resultSetIndex {
+ return nil, xerrors.WithStackTrace(fmt.Errorf(
+ "next result set index %d less than last result set index %d: %w",
+ part.GetResultSetIndex(), r.resultSetIndex, errWrongNextResultSetIndex,
+ ))
+ }
+ r.lastPart = part
+ r.resultSetIndex = part.GetResultSetIndex()
+ }
+ }
+}
+
+func (r *result) NextResultSet(ctx context.Context) (_ query.ResultSet, err error) {
+ onDone := trace.QueryOnResultNextResultSet(r.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*result).NextResultSet"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ return r.nextResultSet(ctx)
+}
+
+func (r *result) Err() error {
+ switch {
+ case len(r.errs) == 0:
+ return nil
+ case len(r.errs) == 1:
+ return r.errs[0]
+ default:
+ return xerrors.WithStackTrace(xerrors.Join(r.errs...))
+ }
+}
diff --git a/internal/query/result_set.go b/internal/query/result_set.go
new file mode 100644
index 000000000..47d90301f
--- /dev/null
+++ b/internal/query/result_set.go
@@ -0,0 +1,96 @@
+package query
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+var _ query.ResultSet = (*resultSet)(nil)
+
+type resultSet struct {
+ index int64
+ recv func() (*Ydb_Query.ExecuteQueryResponsePart, error)
+ columns []*Ydb.Column
+ currentPart *Ydb_Query.ExecuteQueryResponsePart
+ rowIndex int
+ trace *trace.Query
+ done chan struct{}
+}
+
+func newResultSet(
+ recv func() (*Ydb_Query.ExecuteQueryResponsePart, error),
+ part *Ydb_Query.ExecuteQueryResponsePart,
+ t *trace.Query,
+) *resultSet {
+ if t == nil {
+ t = &trace.Query{}
+ }
+
+ return &resultSet{
+ index: part.GetResultSetIndex(),
+ recv: recv,
+ currentPart: part,
+ rowIndex: -1,
+ columns: part.GetResultSet().GetColumns(),
+ trace: t,
+ done: make(chan struct{}),
+ }
+}
+
+func (rs *resultSet) nextRow(ctx context.Context) (*row, error) {
+ rs.rowIndex++
+ select {
+ case <-rs.done:
+ return nil, io.EOF
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ default:
+ if rs.rowIndex == len(rs.currentPart.GetResultSet().GetRows()) {
+ part, err := rs.recv()
+ if err != nil {
+ if xerrors.Is(err, io.EOF) {
+ close(rs.done)
+ }
+
+ return nil, xerrors.WithStackTrace(err)
+ }
+ rs.rowIndex = 0
+ rs.currentPart = part
+ if part == nil {
+ close(rs.done)
+
+ return nil, xerrors.WithStackTrace(io.EOF)
+ }
+ }
+ if rs.index != rs.currentPart.GetResultSetIndex() {
+ close(rs.done)
+
+ return nil, xerrors.WithStackTrace(fmt.Errorf(
+ "received part with result set index = %d, current result set index = %d: %w",
+ rs.index, rs.currentPart.GetResultSetIndex(), errWrongResultSetIndex,
+ ))
+ }
+
+ return newRow(ctx, rs.columns, rs.currentPart.GetResultSet().GetRows()[rs.rowIndex], rs.trace)
+ }
+}
+
+func (rs *resultSet) NextRow(ctx context.Context) (_ query.Row, err error) {
+ onDone := trace.QueryOnResultSetNextRow(rs.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*resultSet).NextRow"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ return rs.nextRow(ctx)
+}
diff --git a/internal/query/result_set_test.go b/internal/query/result_set_test.go
new file mode 100644
index 000000000..a011d2781
--- /dev/null
+++ b/internal/query/result_set_test.go
@@ -0,0 +1,602 @@
+package query
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "go.uber.org/mock/gomock"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestResultSetNext(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ t.Run("OverTwoParts", func(t *testing.T) {
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, io.EOF)
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := stream.Recv()
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ })
+ t.Run("CanceledContext", func(t *testing.T) {
+ ctx, cancel := context.WithCancel(xtest.Context(t))
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := stream.Recv()
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ cancel()
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, context.Canceled)
+ }
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, xerrors.Operation(xerrors.WithStatusCode(
+ Ydb.StatusIds_OVERLOADED,
+ )))
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := nextPart(ctx, stream, nil)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+ if resultSetIndex := part.GetResultSetIndex(); resultSetIndex != 0 {
+ return nil, xerrors.WithStackTrace(fmt.Errorf(
+ "critical violation of the logic: wrong result set index: %d != %d",
+ resultSetIndex, 0,
+ ))
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_OVERLOADED))
+ }
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := nextPart(ctx, stream, nil)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+ if resultSetIndex := part.GetResultSetIndex(); resultSetIndex != 0 {
+ return nil, xerrors.WithStackTrace(fmt.Errorf(
+ "critical violation of the logic: wrong result set index: %d != %d",
+ resultSetIndex, 0,
+ ))
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ }
+ })
+ t.Run("WrongResultSetIndex", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 1,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := nextPart(ctx, stream, nil)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, errWrongResultSetIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ })
+}
diff --git a/internal/query/result_test.go b/internal/query/result_test.go
new file mode 100644
index 000000000..10d408f03
--- /dev/null
+++ b/internal/query/result_test.go
@@ -0,0 +1,895 @@
+package query
+
+import (
+ "context"
+ "io"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "go.uber.org/mock/gomock"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestResultNextResultSet(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx, cancel := context.WithCancel(xtest.Context(t))
+ defer cancel()
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 1,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "d",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "e",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 1,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 2,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "d",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "e",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 2,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, io.EOF)
+ r, _, err := newResult(ctx, stream, nil, nil)
+ require.NoError(t, err)
+ defer r.Close(ctx)
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=5)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=6)")
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ }
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.index)
+ }
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=5)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=6)")
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ }
+ {
+ t.Log("close result")
+ r.Close(context.Background())
+ }
+ {
+ t.Log("nextResultSet")
+ _, err := r.nextResultSet(context.Background())
+ require.ErrorIs(t, err, errClosedResult)
+ }
+ t.Log("check final error")
+ require.NoError(t, r.Err())
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("InterruptStream", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx, cancel := context.WithCancel(xtest.Context(t))
+ defer cancel()
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ r, _, err := newResult(ctx, stream, nil, nil)
+ require.NoError(t, err)
+ defer r.Close(ctx)
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ t.Log("explicit interrupt stream")
+ require.NoError(t, r.closeOnce(ctx))
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(context.Background())
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(context.Background())
+ require.ErrorIs(t, err, errClosedResult)
+ }
+ }
+ {
+ t.Log("nextResultSet")
+ _, err := r.nextResultSet(context.Background())
+ require.ErrorIs(t, err, errClosedResult)
+ }
+ t.Log("check final error")
+ require.ErrorIs(t, r.Err(), errClosedResult)
+ }, xtest.StopAfter(time.Second))
+ })
+ t.Run("WrongResultSetIndex", func(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ ctx, cancel := context.WithCancel(xtest.Context(t))
+ defer cancel()
+ ctrl := gomock.NewController(t)
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 2,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "d",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "e",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 2,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 4,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "4",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 5,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "5",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 1,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "d",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "e",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }, {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: false,
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ r, _, err := newResult(ctx, stream, nil, nil)
+ require.NoError(t, err)
+ defer r.Close(ctx)
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.index)
+ {
+ t.Log("next (row=1)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=2)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=3)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=4)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=5)")
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ t.Log("next (row=6)")
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ }
+ {
+ t.Log("nextResultSet")
+ rs, err := r.nextResultSet(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.index)
+ }
+ {
+ t.Log("nextResultSet")
+ _, err := r.nextResultSet(ctx)
+ require.ErrorIs(t, err, errWrongNextResultSetIndex)
+ }
+ t.Log("check final error")
+ require.ErrorIs(t, r.Err(), errWrongNextResultSetIndex)
+ }, xtest.StopAfter(time.Second))
+ })
+}
diff --git a/internal/query/row.go b/internal/query/row.go
new file mode 100644
index 000000000..476b6aa14
--- /dev/null
+++ b/internal/query/row.go
@@ -0,0 +1,68 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/scanner"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+var _ query.Row = (*row)(nil)
+
+type row struct {
+ ctx context.Context
+ trace *trace.Query
+
+ indexedScanner scanner.IndexedScanner
+ namedScanner scanner.NamedScanner
+ structScanner scanner.StructScanner
+}
+
+func newRow(ctx context.Context, columns []*Ydb.Column, v *Ydb.Value, t *trace.Query) (*row, error) {
+ data := scanner.Data(columns, v.GetItems())
+
+ return &row{
+ ctx: ctx,
+ trace: t,
+ indexedScanner: scanner.Indexed(data),
+ namedScanner: scanner.Named(data),
+ structScanner: scanner.Struct(data),
+ }, nil
+}
+
+func (r row) Scan(dst ...interface{}) (err error) {
+ onDone := trace.QueryOnRowScan(r.trace, &r.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.row.Scan"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ return r.indexedScanner.Scan(dst...)
+}
+
+func (r row) ScanNamed(dst ...scanner.NamedDestination) (err error) {
+ onDone := trace.QueryOnRowScanNamed(r.trace, &r.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.row.ScanNamed"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ return r.namedScanner.ScanNamed(dst...)
+}
+
+func (r row) ScanStruct(dst interface{}, opts ...scanner.ScanStructOption) (err error) {
+ onDone := trace.QueryOnRowScanStruct(r.trace, &r.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.row.ScanStruct"),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ return r.structScanner.ScanStruct(dst, opts...)
+}
diff --git a/internal/query/scanner/data.go b/internal/query/scanner/data.go
new file mode 100644
index 000000000..d1a806097
--- /dev/null
+++ b/internal/query/scanner/data.go
@@ -0,0 +1,36 @@
+package scanner
+
+import (
+ "fmt"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+)
+
+type data struct {
+ columns []*Ydb.Column
+ values []*Ydb.Value
+}
+
+func Data(columns []*Ydb.Column, values []*Ydb.Value) *data {
+ return &data{
+ columns: columns,
+ values: values,
+ }
+}
+
+func (s data) seekByName(name string) (value.Value, error) {
+ for i := range s.columns {
+ if s.columns[i].GetName() == name {
+ return value.FromYDB(s.columns[i].GetType(), s.values[i]), nil
+ }
+ }
+
+ return nil, xerrors.WithStackTrace(fmt.Errorf("'%s': %w", name, errColumnsNotFoundInRow))
+}
+
+func (s data) seekByIndex(idx int) value.Value {
+ return value.FromYDB(s.columns[idx].GetType(), s.values[idx])
+}
diff --git a/internal/query/scanner/errors.go b/internal/query/scanner/errors.go
new file mode 100644
index 000000000..cac104f10
--- /dev/null
+++ b/internal/query/scanner/errors.go
@@ -0,0 +1,13 @@
+package scanner
+
+import (
+ "errors"
+)
+
+var (
+ errColumnsNotFoundInRow = errors.New("some columns not found in row")
+ errFieldsNotFoundInStruct = errors.New("some fields not found in struct")
+ errIncompatibleColumnsAndDestinations = errors.New("incompatible columns and destinations")
+ errDstTypeIsNotAPointer = errors.New("dst type is not a pointer")
+ errDstTypeIsNotAPointerToStruct = errors.New("dst type is not a pointer to struct")
+)
diff --git a/internal/query/scanner/indexed.go b/internal/query/scanner/indexed.go
new file mode 100644
index 000000000..e826a08c0
--- /dev/null
+++ b/internal/query/scanner/indexed.go
@@ -0,0 +1,37 @@
+package scanner
+
+import (
+ "fmt"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+)
+
+type IndexedScanner struct {
+ data *data
+}
+
+func Indexed(data *data) IndexedScanner {
+ return IndexedScanner{
+ data: data,
+ }
+}
+
+func (s IndexedScanner) Scan(dst ...interface{}) (err error) {
+ if len(dst) != len(s.data.columns) {
+ return xerrors.WithStackTrace(
+ fmt.Errorf("%w: %d != %d",
+ errIncompatibleColumnsAndDestinations,
+ len(dst), len(s.data.columns),
+ ),
+ )
+ }
+ for i := range dst {
+ v := s.data.seekByIndex(i)
+ if err := value.CastTo(v, dst[i]); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ }
+
+ return nil
+}
diff --git a/internal/query/scanner/indexed_test.go b/internal/query/scanner/indexed_test.go
new file mode 100644
index 000000000..ac2a9b40d
--- /dev/null
+++ b/internal/query/scanner/indexed_test.go
@@ -0,0 +1,558 @@
+package scanner
+
+import (
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+func TestIndexed(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ s IndexedScanner
+ dst [][]interface{}
+ exp [][]interface{}
+ }{
+ {
+ name: "Ydb.Type_UTF8",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v string) *string { return &v }("")},
+ {func(v []byte) *[]byte { return &v }([]byte(""))},
+ },
+ exp: [][]interface{}{
+ {func(v string) *string { return &v }("test")},
+ {func(v []byte) *[]byte { return &v }([]byte("test"))},
+ },
+ },
+ {
+ name: "Ydb.Type_STRING",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v string) *string { return &v }("")},
+ {func(v []byte) *[]byte { return &v }([]byte(""))},
+ },
+ exp: [][]interface{}{
+ {func(v string) *string { return &v }("test")},
+ {func(v []byte) *[]byte { return &v }([]byte("test"))},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT64",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT64",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT32",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v uint32) *uint32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT32",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v int) *int { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v int) *int { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT16",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v uint32) *uint32 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT16",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT8",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v uint8) *uint8 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v uint32) *uint32 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v uint8) *uint8 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT8",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v int8) *int8 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v int8) *int8 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_BOOL",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v bool) *bool { return &v }(false)},
+ },
+ exp: [][]interface{}{
+ {func(v bool) *bool { return &v }(true)},
+ },
+ },
+ {
+ name: "Ydb.Type_DATE",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATE,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 100500,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(100500)},
+ {func(v int64) *int64 { return &v }(100500)},
+ {func(v int32) *int32 { return &v }(100500)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(8683200000, 0))},
+ },
+ },
+ {
+ name: "Ydb.Type_DATETIME",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATETIME,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 100500,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(100500)},
+ {func(v int64) *int64 { return &v }(100500)},
+ {func(v uint32) *uint32 { return &v }(100500)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(100500, 0))},
+ },
+ },
+ {
+ name: "Ydb.Type_TIMESTAMP",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TIMESTAMP,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 12345678987654321,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(12345678987654321)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(12345678987, 654321000))},
+ },
+ },
+ {
+ name: "Ydb.Type_INTERVAL",
+ s: Indexed(Data(
+ []*Ydb.Column{
+ {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INTERVAL,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 100500,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v time.Duration) *time.Duration { return &v }(time.Duration(0))},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(100500)},
+ {func(v time.Duration) *time.Duration { return &v }(time.Duration(100500000))},
+ },
+ },
+ } {
+ for i := range tt.dst {
+ t.Run(tt.name+"→"+reflect.TypeOf(tt.dst[i][0]).Elem().String(), func(t *testing.T) {
+ err := tt.s.Scan(tt.dst[i]...)
+ require.NoError(t, err)
+ require.Equal(t, tt.exp[i], tt.dst[i])
+ })
+ }
+ }
+}
+
+func TestIndexedIncompatibleColumnsAndDestinations(t *testing.T) {
+ scanner := &IndexedScanner{data: Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ )}
+ var (
+ B string
+ C string
+ )
+ err := scanner.Scan(&B, &C)
+ require.ErrorIs(t, err, errIncompatibleColumnsAndDestinations)
+}
+
+func TestIndexedCastFailed(t *testing.T) {
+ scanner := Indexed(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var A uint64
+ err := scanner.Scan(&A)
+ require.ErrorIs(t, err, value.ErrCannotCast)
+}
diff --git a/internal/query/scanner/named.go b/internal/query/scanner/named.go
new file mode 100644
index 000000000..07f31aa94
--- /dev/null
+++ b/internal/query/scanner/named.go
@@ -0,0 +1,53 @@
+package scanner
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+)
+
+type (
+ NamedScanner struct {
+ data *data
+ }
+ NamedDestination struct {
+ name string
+ ref interface{}
+ }
+)
+
+func NamedRef(columnName string, destinationValueReference interface{}) (dst NamedDestination) {
+ if columnName == "" {
+ panic("columnName must be not empty")
+ }
+ dst.name = columnName
+ v := reflect.TypeOf(destinationValueReference)
+ if v.Kind() != reflect.Ptr {
+ panic(fmt.Errorf("%T is not reference type", destinationValueReference))
+ }
+ dst.ref = destinationValueReference
+
+ return dst
+}
+
+func Named(data *data) NamedScanner {
+ return NamedScanner{
+ data: data,
+ }
+}
+
+func (s NamedScanner) ScanNamed(dst ...NamedDestination) (err error) {
+ for i := range dst {
+ v, err := s.data.seekByName(dst[i].name)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ if err = value.CastTo(v, dst[i].ref); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ }
+
+ return nil
+}
diff --git a/internal/query/scanner/named_test.go b/internal/query/scanner/named_test.go
new file mode 100644
index 000000000..7c3fe9d8b
--- /dev/null
+++ b/internal/query/scanner/named_test.go
@@ -0,0 +1,701 @@
+package scanner
+
+import (
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+func TestNamed(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ s NamedScanner
+ dst [][]interface{}
+ exp [][]interface{}
+ }{
+ {
+ name: "Ydb.Type_UTF8",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v string) *string { return &v }("")},
+ {func(v []byte) *[]byte { return &v }([]byte(""))},
+ },
+ exp: [][]interface{}{
+ {func(v string) *string { return &v }("test")},
+ {func(v []byte) *[]byte { return &v }([]byte("test"))},
+ },
+ },
+ {
+ name: "Ydb.Type_STRING",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v string) *string { return &v }("")},
+ {func(v []byte) *[]byte { return &v }([]byte(""))},
+ },
+ exp: [][]interface{}{
+ {func(v string) *string { return &v }("test")},
+ {func(v []byte) *[]byte { return &v }([]byte("test"))},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT64",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT64",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT32",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v uint32) *uint32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT32",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v int) *int { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v int) *int { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT16",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v uint32) *uint32 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT16",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_UINT8",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v uint8) *uint8 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(123)},
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v uint32) *uint32 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v uint8) *uint8 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_INT8",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v int8) *int8 { return &v }(0)},
+ {func(v float32) *float32 { return &v }(0)},
+ {func(v float64) *float64 { return &v }(0)},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(123)},
+ {func(v int32) *int32 { return &v }(123)},
+ {func(v int8) *int8 { return &v }(123)},
+ {func(v float32) *float32 { return &v }(123)},
+ {func(v float64) *float64 { return &v }(123)},
+ },
+ },
+ {
+ name: "Ydb.Type_BOOL",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v bool) *bool { return &v }(false)},
+ },
+ exp: [][]interface{}{
+ {func(v bool) *bool { return &v }(true)},
+ },
+ },
+ {
+ name: "Ydb.Type_DATE",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATE,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 100500,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v int32) *int32 { return &v }(0)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(100500)},
+ {func(v int64) *int64 { return &v }(100500)},
+ {func(v int32) *int32 { return &v }(100500)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(8683200000, 0))},
+ },
+ },
+ {
+ name: "Ydb.Type_DATETIME",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATETIME,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 100500,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v uint32) *uint32 { return &v }(0)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(100500)},
+ {func(v int64) *int64 { return &v }(100500)},
+ {func(v uint32) *uint32 { return &v }(100500)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(100500, 0))},
+ },
+ },
+ {
+ name: "Ydb.Type_TIMESTAMP",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TIMESTAMP,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 12345678987654321,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(0)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(0, 0))},
+ },
+ exp: [][]interface{}{
+ {func(v uint64) *uint64 { return &v }(12345678987654321)},
+ {func(v time.Time) *time.Time { return &v }(time.Unix(12345678987, 654321000))},
+ },
+ },
+ {
+ name: "Ydb.Type_INTERVAL",
+ s: Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INTERVAL,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 100500,
+ },
+ },
+ },
+ )),
+ dst: [][]interface{}{
+ {func(v int64) *int64 { return &v }(0)},
+ {func(v time.Duration) *time.Duration { return &v }(time.Duration(0))},
+ },
+ exp: [][]interface{}{
+ {func(v int64) *int64 { return &v }(100500)},
+ {func(v time.Duration) *time.Duration { return &v }(time.Duration(100500000))},
+ },
+ },
+ } {
+ for i := range tt.dst {
+ t.Run(tt.name+"→"+reflect.TypeOf(tt.dst[i][0]).Elem().String(), func(t *testing.T) {
+ err := tt.s.ScanNamed(func() (dst []NamedDestination) {
+ for j := range tt.dst[i] {
+ dst = append(dst, NamedRef("a", tt.dst[i][j]))
+ }
+
+ return dst
+ }()...)
+ require.NoError(t, err)
+ require.Equal(t, tt.exp[i], tt.dst[i])
+ })
+ }
+ }
+}
+
+func TestScannerNamedNotFoundByName(t *testing.T) {
+ scanner := Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var s string
+ err := scanner.ScanNamed(NamedRef("b", &s))
+ require.ErrorIs(t, err, errColumnsNotFoundInRow)
+}
+
+func TestScannerNamedOrdering(t *testing.T) {
+ scanner := Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "c",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "A",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "B",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "C",
+ },
+ },
+ },
+ ))
+ var a, b, c string
+ err := scanner.ScanNamed(
+ NamedRef("c", &c),
+ NamedRef("b", &b),
+ NamedRef("a", &a),
+ )
+ require.NoError(t, err)
+ require.Equal(t, "A", a)
+ require.Equal(t, "B", b)
+ require.Equal(t, "C", c)
+}
+
+func TestNamedRef(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ ref interface{}
+ dst NamedDestination
+ panic bool
+ }{
+ {
+ name: "",
+ ref: nil,
+ dst: NamedDestination{},
+ panic: true,
+ },
+ {
+ name: "nil_ref",
+ ref: nil,
+ dst: NamedDestination{},
+ panic: true,
+ },
+ {
+ name: "not_ref",
+ ref: 123,
+ dst: NamedDestination{},
+ panic: true,
+ },
+ {
+ name: "int_ptr",
+ ref: func(v int) *int { return &v }(123),
+ dst: NamedDestination{
+ name: "int_ptr",
+ ref: func(v int) *int { return &v }(123),
+ },
+ panic: false,
+ },
+ {
+ name: "int_dbl_ptr",
+ ref: func(v int) **int {
+ vv := &v
+
+ return &vv
+ }(123),
+ dst: NamedDestination{
+ name: "int_dbl_ptr",
+ ref: func(v int) **int {
+ vv := &v
+
+ return &vv
+ }(123),
+ },
+ panic: false,
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ if tt.panic {
+ defer func() {
+ require.NotNil(t, recover())
+ }()
+ } else {
+ defer func() {
+ require.Nil(t, recover())
+ }()
+ }
+ require.Equal(t, tt.dst, NamedRef(tt.name, tt.ref))
+ })
+ }
+}
+
+func TestNamedCastFailed(t *testing.T) {
+ scanner := Named(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var A uint64
+ err := scanner.ScanNamed(NamedRef("a", &A))
+ require.ErrorIs(t, err, value.ErrCannotCast)
+}
diff --git a/internal/query/scanner/struct.go b/internal/query/scanner/struct.go
new file mode 100644
index 000000000..5f73ff095
--- /dev/null
+++ b/internal/query/scanner/struct.go
@@ -0,0 +1,91 @@
+package scanner
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+)
+
+type scanStructSettings struct {
+ TagName string
+ AllowMissingColumnsFromSelect bool
+ AllowMissingFieldsInStruct bool
+}
+
+type StructScanner struct {
+ data *data
+}
+
+func Struct(data *data) StructScanner {
+ return StructScanner{
+ data: data,
+ }
+}
+
+func fieldName(f reflect.StructField, tagName string) string { //nolint:gocritic
+ if name, has := f.Tag.Lookup(tagName); has {
+ return name
+ }
+
+ return f.Name
+}
+
+func (s StructScanner) ScanStruct(dst interface{}, opts ...ScanStructOption) (err error) {
+ settings := scanStructSettings{
+ TagName: "sql",
+ AllowMissingColumnsFromSelect: false,
+ AllowMissingFieldsInStruct: false,
+ }
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyScanStructOption(&settings)
+ }
+ }
+ ptr := reflect.ValueOf(dst)
+ if ptr.Kind() != reflect.Pointer {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: '%s'", errDstTypeIsNotAPointer, ptr.Kind().String()))
+ }
+ if ptr.Elem().Kind() != reflect.Struct {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: '%s'", errDstTypeIsNotAPointerToStruct, ptr.Elem().Kind().String()))
+ }
+ tt := ptr.Elem().Type()
+ missingColumns := make([]string, 0, len(s.data.columns))
+ existingFields := make(map[string]struct{}, tt.NumField())
+ for i := 0; i < tt.NumField(); i++ {
+ name := fieldName(tt.Field(i), settings.TagName)
+ v, err := s.data.seekByName(name)
+ if err != nil {
+ missingColumns = append(missingColumns, name)
+ } else {
+ if err = value.CastTo(v, ptr.Elem().Field(i).Addr().Interface()); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ existingFields[name] = struct{}{}
+ }
+ }
+
+ if !settings.AllowMissingColumnsFromSelect && len(missingColumns) > 0 {
+ return xerrors.WithStackTrace(
+ fmt.Errorf("%w: '%v'", errColumnsNotFoundInRow, strings.Join(missingColumns, "','")),
+ )
+ }
+
+ if !settings.AllowMissingFieldsInStruct {
+ missingFields := make([]string, 0, tt.NumField())
+ for _, c := range s.data.columns {
+ if _, has := existingFields[c.GetName()]; !has {
+ missingFields = append(missingFields, c.GetName())
+ }
+ }
+ if len(missingFields) > 0 {
+ return xerrors.WithStackTrace(
+ fmt.Errorf("%w: '%v'", errFieldsNotFoundInStruct, strings.Join(missingFields, "','")),
+ )
+ }
+ }
+
+ return nil
+}
diff --git a/internal/query/scanner/struct_options.go b/internal/query/scanner/struct_options.go
new file mode 100644
index 000000000..3146f6750
--- /dev/null
+++ b/internal/query/scanner/struct_options.go
@@ -0,0 +1,40 @@
+package scanner
+
+type (
+ ScanStructOption interface {
+ applyScanStructOption(settings *scanStructSettings)
+ }
+ tagName string
+ allowMissingColumnsFromSelect struct{}
+ allowMissingFieldsInStruct struct{}
+)
+
+var (
+ _ ScanStructOption = tagName("")
+ _ ScanStructOption = allowMissingColumnsFromSelect{}
+ _ ScanStructOption = allowMissingFieldsInStruct{}
+)
+
+func (allowMissingFieldsInStruct) applyScanStructOption(settings *scanStructSettings) {
+ settings.AllowMissingFieldsInStruct = true
+}
+
+func (allowMissingColumnsFromSelect) applyScanStructOption(settings *scanStructSettings) {
+ settings.AllowMissingColumnsFromSelect = true
+}
+
+func (name tagName) applyScanStructOption(settings *scanStructSettings) {
+ settings.TagName = string(name)
+}
+
+func WithTagName(name string) tagName {
+ return tagName(name)
+}
+
+func WithAllowMissingColumnsFromSelect() allowMissingColumnsFromSelect {
+ return allowMissingColumnsFromSelect{}
+}
+
+func WithAllowMissingFieldsInStruct() allowMissingFieldsInStruct {
+ return allowMissingFieldsInStruct{}
+}
diff --git a/internal/query/scanner/struct_test.go b/internal/query/scanner/struct_test.go
new file mode 100644
index 000000000..d6d1918ea
--- /dev/null
+++ b/internal/query/scanner/struct_test.go
@@ -0,0 +1,853 @@
+package scanner
+
+import (
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestFieldName(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ in interface{}
+ out string
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ in: struct {
+ Col0 string
+ }{},
+ out: "Col0",
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ in: struct {
+ Col0 string `sql:"col0"`
+ }{},
+ out: "col0",
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ require.Equal(t, tt.out, fieldName(reflect.ValueOf(tt.in).Type().Field(0), "sql"))
+ })
+ }
+}
+
+func TestStruct(t *testing.T) {
+ newScannerData := func(mapping map[*Ydb.Column]*Ydb.Value) *data {
+ data := &data{
+ columns: make([]*Ydb.Column, 0, len(mapping)),
+ values: make([]*Ydb.Value, 0, len(mapping)),
+ }
+ for c, v := range mapping {
+ data.columns = append(data.columns, c)
+ data.values = append(data.values, v)
+ }
+
+ return data
+ }
+
+ type scanData struct { //nolint:maligned
+ Utf8String string
+ Utf8Bytes []byte
+ StringString string
+ StringBytes []byte
+ Uint64Uint64 uint64
+ Int64Int64 int64
+ Uint32Uint64 uint64
+ Uint32Int64 int64
+ Uint32Uint32 uint32
+ Int32Int64 int64
+ Int32Int32 int32
+ Uint16Uint64 uint64
+ Uint16Int64 int64
+ Uint16Uint32 uint32
+ Uint16Int32 int32
+ Uint16Uint16 uint16
+ Int16Int64 int64
+ Int16Int32 int32
+ Uint8Uint64 uint64
+ Uint8Int64 int64
+ Uint8Uint32 uint32
+ Uint8Int32 int32
+ Uint8Uint16 uint16
+ Int8Int64 int64
+ Int8Int32 int32
+ Int8Int16 int16
+ BoolBool bool
+ DateTime time.Time
+ DatetimeTime time.Time
+ TimestampTime time.Time
+ }
+ var dst scanData
+ err := Struct(newScannerData(map[*Ydb.Column]*Ydb.Value{
+ {
+ Name: "Utf8String",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "A",
+ },
+ },
+ {
+ Name: "Utf8Bytes",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "A",
+ },
+ },
+ {
+ Name: "StringString",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("A"),
+ },
+ },
+ {
+ Name: "StringBytes",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("A"),
+ },
+ },
+ {
+ Name: "Uint64Uint64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ {
+ Name: "Int64Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ {
+ Name: "Uint32Uint64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint32Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint32Uint32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Int32Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "Int32Int32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "Uint16Uint64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint16Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint16Uint32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint16Int32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint16Uint16",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Int16Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "Int16Int32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "Uint8Uint64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint8Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint8Uint32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint8Int32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Uint8Uint16",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Name: "Int8Int64",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "Int8Int32",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "Int8Int16",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ {
+ Name: "BoolBool",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ {
+ Name: "DateTime",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATE,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 100500,
+ },
+ },
+ {
+ Name: "DatetimeTime",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATETIME,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 100500,
+ },
+ },
+ {
+ Name: "TimestampTime",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TIMESTAMP,
+ },
+ },
+ }: {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 12345678987654321,
+ },
+ },
+ })).ScanStruct(&dst)
+ require.NoError(t, err)
+ require.Equal(t, scanData{
+ Utf8String: "A",
+ Utf8Bytes: []byte("A"),
+ StringString: "A",
+ StringBytes: []byte("A"),
+ Uint64Uint64: 123,
+ Int64Int64: 123,
+ Uint32Uint64: 123,
+ Uint32Int64: 123,
+ Uint32Uint32: 123,
+ Int32Int64: 123,
+ Int32Int32: 123,
+ Uint16Uint64: 123,
+ Uint16Int64: 123,
+ Uint16Uint32: 123,
+ Uint16Int32: 123,
+ Uint16Uint16: 123,
+ Int16Int64: 123,
+ Int16Int32: 123,
+ Uint8Uint64: 123,
+ Uint8Int64: 123,
+ Uint8Uint32: 123,
+ Uint8Int32: 123,
+ Uint8Uint16: 123,
+ Int8Int64: 123,
+ Int8Int32: 123,
+ Int8Int16: 123,
+ BoolBool: true,
+ DateTime: time.Unix(8683200000, 0),
+ DatetimeTime: time.Unix(100500, 0),
+ TimestampTime: time.Unix(12345678987, 654321000),
+ }, dst)
+}
+
+func TestStructNotAPointer(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row struct {
+ B string
+ C string
+ }
+ err := scanner.ScanStruct(row)
+ require.ErrorIs(t, err, errDstTypeIsNotAPointer)
+}
+
+func TestStructNotAPointerToStruct(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row string
+ err := scanner.ScanStruct(&row)
+ require.ErrorIs(t, err, errDstTypeIsNotAPointerToStruct)
+}
+
+func TestStructCastFailed(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "A",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row struct {
+ A uint64
+ }
+ err := scanner.ScanStruct(&row)
+ require.ErrorIs(t, err, value.ErrCannotCast)
+}
+
+func TestStructNotFoundColumns(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row struct {
+ B string
+ C string
+ }
+ err := scanner.ScanStruct(&row)
+ require.ErrorIs(t, err, errColumnsNotFoundInRow)
+}
+
+func TestStructWithAllowMissingColumnsFromSelect(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "A",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row struct {
+ A string
+ B string
+ C string
+ }
+ err := scanner.ScanStruct(&row,
+ WithAllowMissingColumnsFromSelect(),
+ )
+ require.NoError(t, err)
+ require.Equal(t, "test", row.A)
+ require.Equal(t, "", row.B)
+ require.Equal(t, "", row.C)
+}
+
+func TestStructNotFoundFields(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "A",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "B",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "C",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row struct {
+ A string
+ }
+ err := scanner.ScanStruct(&row)
+ require.ErrorIs(t, err, errFieldsNotFoundInStruct)
+}
+
+func TestStructWithAllowMissingFieldsInStruct(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "A",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "B",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "C",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ ))
+ var row struct {
+ A string
+ }
+ err := scanner.ScanStruct(&row,
+ WithAllowMissingFieldsInStruct(),
+ )
+ require.NoError(t, err)
+ require.Equal(t, "test", row.A)
+}
+
+func TestStructWithTagName(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "A",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "B",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "C",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "AA",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "BB",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "CC",
+ },
+ },
+ },
+ ))
+ var row struct {
+ A string `test:"A"`
+ B string `test:"B"`
+ C string `test:"C"`
+ }
+ err := scanner.ScanStruct(&row,
+ WithTagName("test"),
+ )
+ require.NoError(t, err)
+ require.Equal(t, "AA", row.A)
+ require.Equal(t, "BB", row.B)
+ require.Equal(t, "CC", row.C)
+}
+
+func TestScannerStructOrdering(t *testing.T) {
+ scanner := Struct(Data(
+ []*Ydb.Column{
+ {
+ Name: "B",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "A",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "C",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "B",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "A",
+ },
+ },
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "C",
+ },
+ },
+ },
+ ))
+ var row struct {
+ A string
+ B string
+ C string
+ }
+ err := scanner.ScanStruct(&row)
+ require.NoError(t, err)
+ require.Equal(t, "A", row.A)
+ require.Equal(t, "B", row.B)
+ require.Equal(t, "C", row.C)
+}
diff --git a/internal/query/session.go b/internal/query/session.go
new file mode 100644
index 000000000..708b36df6
--- /dev/null
+++ b/internal/query/session.go
@@ -0,0 +1,287 @@
+package query
+
+import (
+ "context"
+ "io"
+ "sync/atomic"
+
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+var _ query.Session = (*Session)(nil)
+
+type (
+ Session struct {
+ cfg *config.Config
+ id string
+ nodeID int64
+ grpcClient Ydb_Query_V1.QueryServiceClient
+ statusCode statusCode
+ closeOnce func(ctx context.Context) error
+ checks []func(s *Session) bool
+ }
+ sessionOption func(session *Session)
+)
+
+func withSessionCheck(f func(*Session) bool) sessionOption {
+ return func(s *Session) {
+ s.checks = append(s.checks, f)
+ }
+}
+
+func createSession(
+ ctx context.Context, client Ydb_Query_V1.QueryServiceClient, cfg *config.Config, opts ...sessionOption,
+) (s *Session, finalErr error) {
+ s = &Session{
+ cfg: cfg,
+ grpcClient: client,
+ statusCode: statusUnknown,
+ checks: []func(*Session) bool{
+ func(s *Session) bool {
+ switch s.status() {
+ case statusIdle, statusInUse:
+ return true
+ default:
+ return false
+ }
+ },
+ },
+ }
+ defer func() {
+ if finalErr != nil && s != nil {
+ s.setStatus(statusError)
+ }
+ }()
+
+ for _, opt := range opts {
+ opt(s)
+ }
+
+ onDone := trace.QueryOnSessionCreate(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.createSession"),
+ )
+ defer func() {
+ onDone(s, finalErr)
+ }()
+
+ response, err := client.CreateSession(ctx, &Ydb_Query.CreateSessionRequest{})
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ defer func() {
+ if finalErr != nil {
+ _ = deleteSession(ctx, client, response.GetSessionId())
+ }
+ }()
+
+ s.id = response.GetSessionId()
+ s.nodeID = response.GetNodeId()
+
+ err = s.attach(ctx)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ s.setStatus(statusIdle)
+
+ return s, nil
+}
+
+func (s *Session) attach(ctx context.Context) (finalErr error) {
+ onDone := trace.QueryOnSessionAttach(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).attach"), s)
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ attachCtx, cancelAttach := xcontext.WithCancel(xcontext.ValueOnly(ctx))
+
+ attach, err := s.grpcClient.AttachSession(attachCtx, &Ydb_Query.AttachSessionRequest{
+ SessionId: s.id,
+ })
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ _, err = attach.Recv()
+ if err != nil {
+ cancelAttach()
+
+ return xerrors.WithStackTrace(err)
+ }
+
+ s.closeOnce = xsync.OnceFunc(func(ctx context.Context) (err error) {
+ defer cancelAttach()
+
+ s.setStatus(statusClosing)
+ defer s.setStatus(statusClosed)
+
+ var cancel context.CancelFunc
+ if d := s.cfg.SessionDeleteTimeout(); d > 0 {
+ ctx, cancel = xcontext.WithTimeout(ctx, d)
+ } else {
+ ctx, cancel = xcontext.WithCancel(ctx)
+ }
+ defer cancel()
+
+ if err = deleteSession(ctx, s.grpcClient, s.id); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+ })
+
+ go func() {
+ defer func() {
+ _ = s.closeOnce(xcontext.ValueOnly(ctx))
+ }()
+
+ for {
+ if !s.IsAlive() {
+ return
+ }
+ _, recvErr := attach.Recv()
+ if recvErr != nil {
+ if xerrors.Is(recvErr, io.EOF) {
+ s.setStatus(statusClosed)
+ } else {
+ s.setStatus(statusError)
+ }
+
+ return
+ }
+ }
+ }()
+
+ return nil
+}
+
+func deleteSession(ctx context.Context, client Ydb_Query_V1.QueryServiceClient, sessionID string) error {
+ _, err := client.DeleteSession(ctx,
+ &Ydb_Query.DeleteSessionRequest{
+ SessionId: sessionID,
+ },
+ )
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+func (s *Session) IsAlive() bool {
+ for _, check := range s.checks {
+ if !check(s) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (s *Session) Close(ctx context.Context) (err error) {
+ onDone := trace.QueryOnSessionDelete(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).Close"), s)
+ defer func() {
+ onDone(err)
+ }()
+
+ if s.closeOnce != nil {
+ return s.closeOnce(ctx)
+ }
+
+ return nil
+}
+
+func begin(
+ ctx context.Context,
+ client Ydb_Query_V1.QueryServiceClient,
+ s *Session,
+ txSettings query.TransactionSettings,
+) (*transaction, error) {
+ a := allocator.New()
+ defer a.Free()
+ response, err := client.BeginTransaction(ctx,
+ &Ydb_Query.BeginTransactionRequest{
+ SessionId: s.id,
+ TxSettings: txSettings.ToYDB(a),
+ },
+ )
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return newTransaction(response.GetTxMeta().GetId(), s), nil
+}
+
+func (s *Session) Begin(
+ ctx context.Context,
+ txSettings query.TransactionSettings,
+) (
+ _ query.Transaction, err error,
+) {
+ var tx *transaction
+
+ onDone := trace.QueryOnSessionBegin(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).Begin"), s)
+ defer func() {
+ onDone(err, tx)
+ }()
+
+ tx, err = begin(ctx, s.grpcClient, s, txSettings)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+ tx.s = s
+
+ return tx, nil
+}
+
+func (s *Session) ID() string {
+ return s.id
+}
+
+func (s *Session) NodeID() int64 {
+ return s.nodeID
+}
+
+func (s *Session) status() statusCode {
+ return statusCode(atomic.LoadUint32((*uint32)(&s.statusCode)))
+}
+
+func (s *Session) setStatus(code statusCode) {
+ atomic.StoreUint32((*uint32)(&s.statusCode), uint32(code))
+}
+
+func (s *Session) Status() string {
+ return s.status().String()
+}
+
+func (s *Session) Execute(
+ ctx context.Context, q string, opts ...options.ExecuteOption,
+) (_ query.Transaction, _ query.Result, err error) {
+ onDone := trace.QueryOnSessionExecute(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).Execute"), s, q)
+ defer func() {
+ onDone(err)
+ }()
+
+ tx, r, err := execute(ctx, s, s.grpcClient, q, options.ExecuteSettings(opts...))
+ if err != nil {
+ return nil, nil, xerrors.WithStackTrace(err)
+ }
+
+ return tx, r, nil
+}
diff --git a/internal/query/session_status.go b/internal/query/session_status.go
new file mode 100644
index 000000000..134ade32d
--- /dev/null
+++ b/internal/query/session_status.go
@@ -0,0 +1,37 @@
+package query
+
+import (
+ "fmt"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/session"
+)
+
+type statusCode uint32
+
+const (
+ statusUnknown = statusCode(iota)
+ statusIdle
+ statusInUse
+ statusClosing
+ statusClosed
+ statusError
+)
+
+func (s statusCode) String() string {
+ switch s {
+ case statusUnknown:
+ return session.StatusUnknown
+ case statusIdle:
+ return session.StatusIdle
+ case statusInUse:
+ return session.StatusInUse
+ case statusClosing:
+ return session.StatusClosing
+ case statusClosed:
+ return session.StatusClosed
+ case statusError:
+ return session.StatusError
+ default:
+ return fmt.Sprintf("Unknown%d", s)
+ }
+}
diff --git a/internal/query/session_test.go b/internal/query/session_test.go
new file mode 100644
index 000000000..b75faf5d7
--- /dev/null
+++ b/internal/query/session_test.go
@@ -0,0 +1,56 @@
+package query
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "go.uber.org/mock/gomock"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+)
+
+func TestBegin(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.BeginTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ TxMeta: &Ydb_Query.TransactionMeta{
+ Id: "123",
+ },
+ }, nil)
+ t.Log("begin")
+ tx, err := begin(ctx, service, &Session{id: "123"}, query.TxSettings())
+ require.NoError(t, err)
+ require.Equal(t, "123", tx.id)
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
+ t.Log("begin")
+ _, err := begin(ctx, service, &Session{id: "123"}, query.TxSettings())
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ t.Log("begin")
+ _, err := begin(ctx, service, &Session{id: "123"}, query.TxSettings())
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ })
+}
diff --git a/internal/query/transaction.go b/internal/query/transaction.go
new file mode 100644
index 000000000..fbfcd9151
--- /dev/null
+++ b/internal/query/transaction.go
@@ -0,0 +1,81 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+var _ query.Transaction = (*transaction)(nil)
+
+type transaction struct {
+ id string
+ s *Session
+}
+
+func newTransaction(id string, s *Session) *transaction {
+ return &transaction{
+ id: id,
+ s: s,
+ }
+}
+
+func (tx transaction) ID() string {
+ return tx.id
+}
+
+func (tx transaction) Execute(ctx context.Context, q string, opts ...options.TxExecuteOption) (
+ r query.Result, finalErr error,
+) {
+ onDone := trace.QueryOnTxExecute(tx.s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.transaction.Execute"), tx.s, tx, q)
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ _, res, err := execute(ctx, tx.s, tx.s.grpcClient, q, options.TxExecuteSettings(tx.id, opts...).ExecuteSettings)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return res, nil
+}
+
+func commitTx(ctx context.Context, client Ydb_Query_V1.QueryServiceClient, sessionID, txID string) error {
+ _, err := client.CommitTransaction(ctx, &Ydb_Query.CommitTransactionRequest{
+ SessionId: sessionID,
+ TxId: txID,
+ })
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+func (tx transaction) CommitTx(ctx context.Context) (err error) {
+ return commitTx(ctx, tx.s.grpcClient, tx.s.id, tx.id)
+}
+
+func rollback(ctx context.Context, client Ydb_Query_V1.QueryServiceClient, sessionID, txID string) error {
+ _, err := client.RollbackTransaction(ctx, &Ydb_Query.RollbackTransactionRequest{
+ SessionId: sessionID,
+ TxId: txID,
+ })
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+func (tx transaction) Rollback(ctx context.Context) (err error) {
+ return rollback(ctx, tx.s.grpcClient, tx.s.id, tx.id)
+}
diff --git a/internal/query/transaction_test.go b/internal/query/transaction_test.go
new file mode 100644
index 000000000..83ecdfc6c
--- /dev/null
+++ b/internal/query/transaction_test.go
@@ -0,0 +1,233 @@
+package query
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+ "go.uber.org/mock/gomock"
+ "google.golang.org/grpc"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+)
+
+func TestCommitTx(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(
+ &Ydb_Query.CommitTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil,
+ )
+ t.Log("commit")
+ err := commitTx(ctx, service, "123", "456")
+ require.NoError(t, err)
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(
+ nil, grpcStatus.Error(grpcCodes.Unavailable, ""),
+ )
+ t.Log("commit")
+ err := commitTx(ctx, service, "123", "456")
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ t.Log("commit")
+ err := commitTx(ctx, service, "123", "456")
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ })
+}
+
+func TestRollback(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().RollbackTransaction(gomock.Any(), gomock.Any()).Return(
+ &Ydb_Query.RollbackTransactionResponse{
+ Status: Ydb.StatusIds_SUCCESS,
+ }, nil,
+ )
+ t.Log("rollback")
+ err := rollback(ctx, service, "123", "456")
+ require.NoError(t, err)
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().RollbackTransaction(gomock.Any(), gomock.Any()).Return(
+ nil, grpcStatus.Error(grpcCodes.Unavailable, ""),
+ )
+ t.Log("rollback")
+ err := rollback(ctx, service, "123", "456")
+ require.Error(t, err)
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ service := NewMockQueryServiceClient(ctrl)
+ service.EXPECT().RollbackTransaction(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ t.Log("rollback")
+ err := rollback(ctx, service, "123", "456")
+ require.Error(t, err)
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ })
+}
+
+type testExecuteSettings struct {
+ execMode options.ExecMode
+ statsMode options.StatsMode
+ txControl *query.TransactionControl
+ syntax options.Syntax
+ params *params.Parameters
+ callOptions []grpc.CallOption
+}
+
+func (s testExecuteSettings) ExecMode() options.ExecMode {
+ return s.execMode
+}
+
+func (s testExecuteSettings) StatsMode() options.StatsMode {
+ return s.statsMode
+}
+
+func (s testExecuteSettings) TxControl() *query.TransactionControl {
+ return s.txControl
+}
+
+func (s testExecuteSettings) Syntax() options.Syntax {
+ return s.syntax
+}
+
+func (s testExecuteSettings) Params() *params.Parameters {
+ return s.params
+}
+
+func (s testExecuteSettings) CallOptions() []grpc.CallOption {
+ return s.callOptions
+}
+
+var _ executeConfig = testExecuteSettings{}
+
+func TestTxExecuteSettings(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ txID string
+ txOpts []options.TxExecuteOption
+ settings executeConfig
+ }{
+ {
+ name: "WithTxID",
+ txID: "test",
+ txOpts: nil,
+ settings: testExecuteSettings{
+ execMode: options.ExecModeExecute,
+ statsMode: options.StatsModeNone,
+ txControl: query.TxControl(query.WithTxID("test")),
+ syntax: options.SyntaxYQL,
+ },
+ },
+ {
+ name: "WithStats",
+ txOpts: []options.TxExecuteOption{
+ options.WithStatsMode(options.StatsModeFull),
+ },
+ settings: testExecuteSettings{
+ execMode: options.ExecModeExecute,
+ statsMode: options.StatsModeFull,
+ txControl: query.TxControl(query.WithTxID("")),
+ syntax: options.SyntaxYQL,
+ },
+ },
+ {
+ name: "WithExecMode",
+ txOpts: []options.TxExecuteOption{
+ options.WithExecMode(options.ExecModeExplain),
+ },
+ settings: testExecuteSettings{
+ execMode: options.ExecModeExplain,
+ statsMode: options.StatsModeNone,
+ txControl: query.TxControl(query.WithTxID("")),
+ syntax: options.SyntaxYQL,
+ },
+ },
+ {
+ name: "WithSyntax",
+ txOpts: []options.TxExecuteOption{
+ options.WithSyntax(options.SyntaxPostgreSQL),
+ },
+ settings: testExecuteSettings{
+ execMode: options.ExecModeExecute,
+ statsMode: options.StatsModeNone,
+ txControl: query.TxControl(query.WithTxID("")),
+ syntax: options.SyntaxPostgreSQL,
+ },
+ },
+ {
+ name: "WithGrpcOptions",
+ txOpts: []options.TxExecuteOption{
+ options.WithCallOptions(grpc.CallContentSubtype("test")),
+ },
+ settings: testExecuteSettings{
+ execMode: options.ExecModeExecute,
+ statsMode: options.StatsModeNone,
+ txControl: query.TxControl(query.WithTxID("")),
+ syntax: options.SyntaxYQL,
+ callOptions: []grpc.CallOption{
+ grpc.CallContentSubtype("test"),
+ },
+ },
+ },
+ {
+ name: "WithParams",
+ txOpts: []options.TxExecuteOption{
+ options.WithParameters(
+ params.Builder{}.Param("$a").Text("A").Build(),
+ ),
+ },
+ settings: testExecuteSettings{
+ execMode: options.ExecModeExecute,
+ statsMode: options.StatsModeNone,
+ txControl: query.TxControl(query.WithTxID("")),
+ syntax: options.SyntaxYQL,
+ params: params.Builder{}.Param("$a").Text("A").Build(),
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ a := allocator.New()
+ settings := options.TxExecuteSettings(tt.txID, tt.txOpts...).ExecuteSettings
+ require.Equal(t, tt.settings.Syntax(), settings.Syntax())
+ require.Equal(t, tt.settings.ExecMode(), settings.ExecMode())
+ require.Equal(t, tt.settings.StatsMode(), settings.StatsMode())
+ require.Equal(t, tt.settings.TxControl().ToYDB(a).String(), settings.TxControl().ToYDB(a).String())
+ require.Equal(t, tt.settings.Params().ToYDB(a), settings.Params().ToYDB(a))
+ require.Equal(t, tt.settings.CallOptions(), settings.CallOptions())
+ })
+ }
+}
diff --git a/internal/query/tx/control.go b/internal/query/tx/control.go
new file mode 100644
index 000000000..f6e6f15d5
--- /dev/null
+++ b/internal/query/tx/control.go
@@ -0,0 +1,165 @@
+package tx
+
+import (
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+)
+
+var (
+ _ interface {
+ ToYDB(a *allocator.Allocator) *Ydb_Query.TransactionControl
+ } = (*Control)(nil)
+ _ Selector = (*Settings)(nil)
+)
+
+type (
+ Selector interface {
+ applyTxSelector(a *allocator.Allocator, txControl *Ydb_Query.TransactionControl)
+ }
+ ControlOption interface {
+ applyTxControlOption(txControl *Control)
+ }
+ Control struct {
+ selector Selector
+ commit bool
+ }
+ Identifier interface {
+ ID() string
+ }
+)
+
+func (ctrl *Control) ToYDB(a *allocator.Allocator) *Ydb_Query.TransactionControl {
+ if ctrl == nil {
+ return nil
+ }
+
+ txControl := a.QueryTransactionControl()
+ ctrl.selector.applyTxSelector(a, txControl)
+ txControl.CommitTx = ctrl.commit
+
+ return txControl
+}
+
+var (
+ _ ControlOption = beginTxOptions{}
+ _ Selector = beginTxOptions{}
+)
+
+type beginTxOptions []Option
+
+func (opts beginTxOptions) applyTxControlOption(txControl *Control) {
+ txControl.selector = opts
+}
+
+func (opts beginTxOptions) applyTxSelector(a *allocator.Allocator, txControl *Ydb_Query.TransactionControl) {
+ selector := a.QueryTransactionControlBeginTx()
+ selector.BeginTx = a.QueryTransactionSettings()
+ for _, opt := range opts {
+ if opt != nil {
+ opt.ApplyTxSettingsOption(a, selector.BeginTx)
+ }
+ }
+ txControl.TxSelector = selector
+}
+
+// BeginTx returns selector transaction control option
+func BeginTx(opts ...Option) beginTxOptions {
+ return opts
+}
+
+var (
+ _ ControlOption = txIDTxControlOption("")
+ _ Selector = txIDTxControlOption("")
+)
+
+type txIDTxControlOption string
+
+func (id txIDTxControlOption) applyTxControlOption(txControl *Control) {
+ txControl.selector = id
+}
+
+func (id txIDTxControlOption) applyTxSelector(a *allocator.Allocator, txControl *Ydb_Query.TransactionControl) {
+ selector := a.QueryTransactionControlTxID()
+ selector.TxId = string(id)
+ txControl.TxSelector = selector
+}
+
+func WithTx(t Identifier) txIDTxControlOption {
+ return txIDTxControlOption(t.ID())
+}
+
+func WithTxID(txID string) txIDTxControlOption {
+ return txIDTxControlOption(txID)
+}
+
+type commitTxOption struct{}
+
+func (c commitTxOption) applyTxControlOption(txControl *Control) {
+ txControl.commit = true
+}
+
+// CommitTx returns commit transaction control option
+func CommitTx() ControlOption {
+ return commitTxOption{}
+}
+
+// NewControl makes transaction control from given options
+func NewControl(opts ...ControlOption) *Control {
+ txControl := &Control{
+ selector: BeginTx(WithSerializableReadWrite()),
+ commit: false,
+ }
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyTxControlOption(txControl)
+ }
+ }
+
+ return txControl
+}
+
+func NoTx() *Control {
+ return nil
+}
+
+// DefaultTxControl returns default transaction control with serializable read-write isolation mode and auto-commit
+func DefaultTxControl() *Control {
+ return NewControl(
+ BeginTx(WithSerializableReadWrite()),
+ CommitTx(),
+ )
+}
+
+// SerializableReadWriteTxControl returns transaction control with serializable read-write isolation mode
+func SerializableReadWriteTxControl(opts ...ControlOption) *Control {
+ return NewControl(
+ append([]ControlOption{
+ BeginTx(WithSerializableReadWrite()),
+ }, opts...)...,
+ )
+}
+
+// OnlineReadOnlyTxControl returns online read-only transaction control
+func OnlineReadOnlyTxControl(opts ...OnlineReadOnlyOption) *Control {
+ return NewControl(
+ BeginTx(WithOnlineReadOnly(opts...)),
+ CommitTx(), // open transactions not supported for OnlineReadOnly
+ )
+}
+
+// StaleReadOnlyTxControl returns stale read-only transaction control
+func StaleReadOnlyTxControl() *Control {
+ return NewControl(
+ BeginTx(WithStaleReadOnly()),
+ CommitTx(), // open transactions not supported for StaleReadOnly
+ )
+}
+
+// SnapshotReadOnlyTxControl returns snapshot read-only transaction control
+func SnapshotReadOnlyTxControl() *Control {
+ return NewControl(
+ BeginTx(WithSnapshotReadOnly()),
+ CommitTx(), // open transactions not supported for StaleReadOnly
+ )
+}
diff --git a/internal/query/tx/settings.go b/internal/query/tx/settings.go
new file mode 100644
index 000000000..ac051d132
--- /dev/null
+++ b/internal/query/tx/settings.go
@@ -0,0 +1,149 @@
+package tx
+
+import (
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+)
+
+var (
+ serializableReadWrite = &Ydb_Query.TransactionSettings_SerializableReadWrite{
+ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
+ }
+ staleReadOnly = &Ydb_Query.TransactionSettings_StaleReadOnly{
+ StaleReadOnly: &Ydb_Query.StaleModeSettings{},
+ }
+ snapshotReadOnly = &Ydb_Query.TransactionSettings_SnapshotReadOnly{
+ SnapshotReadOnly: &Ydb_Query.SnapshotModeSettings{},
+ }
+ onlineReadOnlyAllowInconsistentReads = &Ydb_Query.TransactionSettings_OnlineReadOnly{
+ OnlineReadOnly: &Ydb_Query.OnlineModeSettings{AllowInconsistentReads: true},
+ }
+ onlineReadOnlyForbidInconsistentReads = &Ydb_Query.TransactionSettings_OnlineReadOnly{
+ OnlineReadOnly: &Ydb_Query.OnlineModeSettings{AllowInconsistentReads: false},
+ }
+)
+
+// Transaction settings options
+type (
+ Option interface {
+ ApplyTxSettingsOption(a *allocator.Allocator, txSettings *Ydb_Query.TransactionSettings)
+ }
+ Settings []Option
+)
+
+func (opts Settings) applyTxSelector(a *allocator.Allocator, txControl *Ydb_Query.TransactionControl) {
+ beginTx := a.QueryTransactionControlBeginTx()
+ beginTx.BeginTx = a.QueryTransactionSettings()
+ for _, opt := range opts {
+ if opt != nil {
+ opt.ApplyTxSettingsOption(a, beginTx.BeginTx)
+ }
+ }
+ txControl.TxSelector = beginTx
+}
+
+func (opts Settings) ToYDB(a *allocator.Allocator) *Ydb_Query.TransactionSettings {
+ txSettings := a.QueryTransactionSettings()
+ for _, opt := range opts {
+ if opt != nil {
+ opt.ApplyTxSettingsOption(a, txSettings)
+ }
+ }
+
+ return txSettings
+}
+
+// NewSettings returns transaction settings
+func NewSettings(opts ...Option) Settings {
+ return opts
+}
+
+func WithDefaultTxMode() Option {
+ return WithSerializableReadWrite()
+}
+
+var _ Option = serializableReadWriteTxSettingsOption{}
+
+type serializableReadWriteTxSettingsOption struct{}
+
+func (o serializableReadWriteTxSettingsOption) ApplyTxSettingsOption(
+ a *allocator.Allocator, txSettings *Ydb_Query.TransactionSettings,
+) {
+ txSettings.TxMode = serializableReadWrite
+}
+
+func WithSerializableReadWrite() Option {
+ return serializableReadWriteTxSettingsOption{}
+}
+
+var _ Option = snapshotReadOnlyTxSettingsOption{}
+
+type snapshotReadOnlyTxSettingsOption struct{}
+
+func (snapshotReadOnlyTxSettingsOption) ApplyTxSettingsOption(
+ a *allocator.Allocator, settings *Ydb_Query.TransactionSettings,
+) {
+ settings.TxMode = snapshotReadOnly
+}
+
+func WithSnapshotReadOnly() Option {
+ return snapshotReadOnlyTxSettingsOption{}
+}
+
+var _ Option = staleReadOnlySettingsOption{}
+
+type staleReadOnlySettingsOption struct{}
+
+func (staleReadOnlySettingsOption) ApplyTxSettingsOption(
+ a *allocator.Allocator, settings *Ydb_Query.TransactionSettings,
+) {
+ settings.TxMode = staleReadOnly
+}
+
+func WithStaleReadOnly() Option {
+ return staleReadOnlySettingsOption{}
+}
+
+type (
+ onlineReadOnly bool
+ OnlineReadOnlyOption interface {
+ applyTxOnlineReadOnlyOption(opt *onlineReadOnly)
+ }
+)
+
+var _ OnlineReadOnlyOption = inconsistentReadsTxOnlineReadOnlyOption{}
+
+type inconsistentReadsTxOnlineReadOnlyOption struct{}
+
+func (i inconsistentReadsTxOnlineReadOnlyOption) applyTxOnlineReadOnlyOption(b *onlineReadOnly) {
+ *b = true
+}
+
+func WithInconsistentReads() OnlineReadOnlyOption {
+ return inconsistentReadsTxOnlineReadOnlyOption{}
+}
+
+var _ Option = onlineReadOnlySettingsOption{}
+
+type onlineReadOnlySettingsOption []OnlineReadOnlyOption
+
+func (opts onlineReadOnlySettingsOption) ApplyTxSettingsOption(
+ a *allocator.Allocator, settings *Ydb_Query.TransactionSettings,
+) {
+ var ro onlineReadOnly
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyTxOnlineReadOnlyOption(&ro)
+ }
+ }
+ if ro {
+ settings.TxMode = onlineReadOnlyAllowInconsistentReads
+ } else {
+ settings.TxMode = onlineReadOnlyForbidInconsistentReads
+ }
+}
+
+func WithOnlineReadOnly(opts ...OnlineReadOnlyOption) onlineReadOnlySettingsOption {
+ return opts
+}
diff --git a/internal/ratelimiter/client.go b/internal/ratelimiter/client.go
index 8705d7897..eec07b118 100644
--- a/internal/ratelimiter/client.go
+++ b/internal/ratelimiter/client.go
@@ -33,14 +33,15 @@ func (c *Client) Close(ctx context.Context) error {
if c == nil {
return xerrors.WithStackTrace(errNilClient)
}
+
return nil
}
-func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) (*Client, error) {
+func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) *Client {
return &Client{
config: config,
service: Ydb_RateLimiter_V1.NewRateLimiterServiceClient(cc),
- }, nil
+ }
}
func (c *Client) CreateResource(
@@ -57,6 +58,7 @@ func (c *Client) CreateResource(
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -87,6 +89,7 @@ func (c *Client) createResource(
operation.ModeSync,
),
})
+
return
}
@@ -104,6 +107,7 @@ func (c *Client) AlterResource(
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -134,6 +138,7 @@ func (c *Client) alterResource(
operation.ModeSync,
),
})
+
return
}
@@ -151,6 +156,7 @@ func (c *Client) DropResource(
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -173,6 +179,7 @@ func (c *Client) dropResource(
operation.ModeSync,
),
})
+
return
}
@@ -187,10 +194,12 @@ func (c *Client) ListResource(
}
call := func(ctx context.Context) (err error) {
list, err = c.listResource(ctx, coordinationNodePath, resourcePath, recursive)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err := call(ctx)
+
return list, err
}
err := retry.Retry(ctx, call,
@@ -198,6 +207,7 @@ func (c *Client) ListResource(
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
)
+
return list, err
}
@@ -229,6 +239,7 @@ func (c *Client) listResource(
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return result.GetResourcePaths(), nil
}
@@ -242,10 +253,12 @@ func (c *Client) DescribeResource(
}
call := func(ctx context.Context) error {
resource, err = c.describeResource(ctx, coordinationNodePath, resourcePath)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err = call(ctx)
+
return
}
err = retry.Retry(ctx, call,
@@ -253,6 +266,7 @@ func (c *Client) DescribeResource(
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
)
+
return
}
@@ -315,6 +329,7 @@ func (c *Client) AcquireResource(
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
diff --git a/internal/ratelimiter/config/config.go b/internal/ratelimiter/config/config.go
index 8f9aca3c7..d0761f779 100644
--- a/internal/ratelimiter/config/config.go
+++ b/internal/ratelimiter/config/config.go
@@ -6,8 +6,6 @@ import (
)
// Config is a configuration of ratelimiter client
-//
-//nolint:maligned
type Config struct {
config.Common
@@ -39,10 +37,11 @@ func New(opts ...Option) Config {
c := Config{
trace: &trace.Ratelimiter{},
}
- for _, o := range opts {
- if o != nil {
- o(&c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&c)
}
}
+
return c
}
diff --git a/internal/ratelimiter/errors/errors.go b/internal/ratelimiter/errors/errors.go
index 277b93371..761cf25c7 100644
--- a/internal/ratelimiter/errors/errors.go
+++ b/internal/ratelimiter/errors/errors.go
@@ -33,6 +33,7 @@ func NewAcquire(amoount uint64, err error) ratelimiter.AcquireError {
func IsAcquireError(err error) bool {
var ae *acquireError
+
return xerrors.As(err, &ae)
}
@@ -41,5 +42,6 @@ func ToAcquireError(err error) ratelimiter.AcquireError {
if xerrors.As(err, &ae) {
return ae
}
+
return nil
}
diff --git a/internal/ratelimiter/options/acquire.go b/internal/ratelimiter/options/acquire.go
index 395ccf8d3..1febf3e63 100644
--- a/internal/ratelimiter/options/acquire.go
+++ b/internal/ratelimiter/options/acquire.go
@@ -74,10 +74,11 @@ func NewAcquire(opts ...AcquireOption) Acquire {
h := &acquireOptionsHolder{
acquireType: AcquireTypeDefault,
}
- for _, o := range opts {
- if o != nil {
- o(h)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(h)
}
}
+
return h
}
diff --git a/internal/repeater/repeater.go b/internal/repeater/repeater.go
index bb24c2f2c..8cb2fb0c0 100644
--- a/internal/repeater/repeater.go
+++ b/internal/repeater/repeater.go
@@ -78,6 +78,7 @@ func EventType(ctx context.Context) Event {
if eventType, ok := ctx.Value(ctxEventTypeKey{}).(Event); ok {
return eventType
}
+
return EventUnknown
}
@@ -107,9 +108,9 @@ func New(
trace: &trace.Driver{},
}
- for _, o := range opts {
- if o != nil {
- o(r)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(r)
}
}
@@ -146,7 +147,7 @@ func (r *repeater) wakeUp(ctx context.Context, e Event) (err error) {
ctx = WithEvent(ctx, e)
onDone := trace.DriverOnRepeaterWakeUp(r.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/repeater.(*repeater).wakeUp"),
r.name, e,
)
defer func() {
diff --git a/internal/repeater/repeater_test.go b/internal/repeater/repeater_test.go
index c6af53a58..6749ac19a 100644
--- a/internal/repeater/repeater_test.go
+++ b/internal/repeater/repeater_test.go
@@ -20,6 +20,7 @@ func TestRepeaterNoWakeUpsAfterStop(t *testing.T) {
r := New(context.Background(), interval, func(ctx context.Context) (err error) {
wakeUpStart <- struct{}{}
<-wakeUpDone
+
return nil
}, WithClock(fakeClock))
@@ -83,6 +84,7 @@ func TestRepeaterForceLogBackoff(t *testing.T) {
}
lastWakeUp = fakeClock.Now()
wakeUps++
+
return fmt.Errorf("special error for force with log backoff")
}, WithClock(fakeClock))
defer r.Stop()
diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go
new file mode 100644
index 000000000..19c91de52
--- /dev/null
+++ b/internal/scanner/scanner.go
@@ -0,0 +1,145 @@
+package scanner
+
+import (
+ "io"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/decimal"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+// RawValue scanning non-primitive yql types or for own implementation scanner native API
+type RawValue interface {
+ Path() string
+ WritePathTo(w io.Writer) (n int64, err error)
+ Type() types.Type
+ Bool() (v bool)
+ Int8() (v int8)
+ Uint8() (v uint8)
+ Int16() (v int16)
+ Uint16() (v uint16)
+ Int32() (v int32)
+ Uint32() (v uint32)
+ Int64() (v int64)
+ Uint64() (v uint64)
+ Float() (v float32)
+ Double() (v float64)
+ Date() (v time.Time)
+ Datetime() (v time.Time)
+ Timestamp() (v time.Time)
+ Interval() (v time.Duration)
+ TzDate() (v time.Time)
+ TzDatetime() (v time.Time)
+ TzTimestamp() (v time.Time)
+ String() (v []byte)
+ UTF8() (v string)
+ YSON() (v []byte)
+ JSON() (v []byte)
+ UUID() (v [16]byte)
+ JSONDocument() (v []byte)
+ DyNumber() (v string)
+ Value() value.Value
+
+ // Any returns any primitive or optional value.
+ // Currently, it may return one of these types:
+ //
+ // bool
+ // int8
+ // uint8
+ // int16
+ // uint16
+ // int32
+ // uint32
+ // int64
+ // uint64
+ // float32
+ // float64
+ // []byte
+ // string
+ // [16]byte
+ //
+ Any() interface{}
+
+ // Unwrap unwraps current item under scan interpreting it as Optional types.
+ Unwrap()
+ AssertType(t types.Type) bool
+ IsNull() bool
+ IsOptional() bool
+
+ // ListIn interprets current item under scan as a ydb's list.
+ // It returns the size of the nested items.
+ // If current item under scan is not a list types, it returns -1.
+ ListIn() (size int)
+
+ // ListItem selects current item i-th element as an item to scan.
+ // ListIn() must be called before.
+ ListItem(i int)
+
+ // ListOut leaves list entered before by ListIn() call.
+ ListOut()
+
+ // TupleIn interprets current item under scan as a ydb's tuple.
+ // It returns the size of the nested items.
+ TupleIn() (size int)
+
+ // TupleItem selects current item i-th element as an item to scan.
+ // Note that TupleIn() must be called before.
+ // It panics if it is out of bounds.
+ TupleItem(i int)
+
+ // TupleOut leaves tuple entered before by TupleIn() call.
+ TupleOut()
+
+ // StructIn interprets current item under scan as a ydb's struct.
+ // It returns the size of the nested items – the struct fields values.
+ // If there is no current item under scan it returns -1.
+ StructIn() (size int)
+
+ // StructField selects current item i-th field value as an item to scan.
+ // Note that StructIn() must be called before.
+ // It panics if i is out of bounds.
+ StructField(i int) (name string)
+
+ // StructOut leaves struct entered before by StructIn() call.
+ StructOut()
+
+ // DictIn interprets current item under scan as a ydb's dict.
+ // It returns the size of the nested items pairs.
+ // If there is no current item under scan it returns -1.
+ DictIn() (size int)
+
+ // DictKey selects current item i-th pair key as an item to scan.
+ // Note that DictIn() must be called before.
+ // It panics if i is out of bounds.
+ DictKey(i int)
+
+ // DictPayload selects current item i-th pair value as an item to scan.
+ // Note that DictIn() must be called before.
+ // It panics if i is out of bounds.
+ DictPayload(i int)
+
+ // DictOut leaves dict entered before by DictIn() call.
+ DictOut()
+
+ // Variant unwraps current item under scan interpreting it as Variant types.
+ // It returns non-empty name of a field that is filled for struct-based
+ // variant.
+ // It always returns an index of filled field of a Type.
+ Variant() (name string, index uint32)
+
+ // Decimal returns decimal value represented by big-endian 128 bit signed integer.
+ Decimal(t types.Type) (v [16]byte)
+
+ // UnwrapDecimal returns decimal value represented by big-endian 128 bit signed
+ // integer and its types information.
+ UnwrapDecimal() decimal.Decimal
+ IsDecimal() bool
+ Err() error
+}
+
+// Scanner scanning raw ydb types
+type Scanner interface {
+ // UnmarshalYDB must be implemented on client-side for unmarshal raw ydb value.
+ UnmarshalYDB(raw RawValue) error
+}
diff --git a/internal/scheme/client.go b/internal/scheme/client.go
index 22428fe41..6f46ed736 100644
--- a/internal/scheme/client.go
+++ b/internal/scheme/client.go
@@ -34,19 +34,20 @@ func (c *Client) Close(_ context.Context) error {
if c == nil {
return xerrors.WithStackTrace(errNilClient)
}
+
return nil
}
-func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) (*Client, error) {
+func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) *Client {
return &Client{
config: config,
service: Ydb_Scheme_V1.NewSchemeServiceClient(cc),
- }, nil
+ }
}
func (c *Client) MakeDirectory(ctx context.Context, path string) (finalErr error) {
onDone := trace.SchemeOnMakeDirectory(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).MakeDirectory"),
path,
)
defer func() {
@@ -58,6 +59,7 @@ func (c *Client) MakeDirectory(ctx context.Context, path string) (finalErr error
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -78,12 +80,13 @@ func (c *Client) makeDirectory(ctx context.Context, path string) (err error) {
),
},
)
+
return xerrors.WithStackTrace(err)
}
func (c *Client) RemoveDirectory(ctx context.Context, path string) (finalErr error) {
onDone := trace.SchemeOnRemoveDirectory(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).RemoveDirectory"),
path,
)
defer func() {
@@ -95,6 +98,7 @@ func (c *Client) RemoveDirectory(ctx context.Context, path string) (finalErr err
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -115,20 +119,25 @@ func (c *Client) removeDirectory(ctx context.Context, path string) (err error) {
),
},
)
+
return xerrors.WithStackTrace(err)
}
func (c *Client) ListDirectory(ctx context.Context, path string) (d scheme.Directory, finalErr error) {
- onDone := trace.SchemeOnListDirectory(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.SchemeOnListDirectory(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).ListDirectory"),
+ )
defer func() {
onDone(finalErr)
}()
call := func(ctx context.Context) (err error) {
d, err = c.listDirectory(ctx, path)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err := call(ctx)
+
return d, xerrors.WithStackTrace(err)
}
err := retry.Retry(ctx, call,
@@ -136,6 +145,7 @@ func (c *Client) ListDirectory(ctx context.Context, path string) (d scheme.Direc
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
)
+
return d, xerrors.WithStackTrace(err)
}
@@ -165,15 +175,16 @@ func (c *Client) listDirectory(ctx context.Context, path string) (scheme.Directo
if err != nil {
return d, xerrors.WithStackTrace(err)
}
- d.From(result.Self)
- d.Children = make([]scheme.Entry, len(result.Children))
- putEntry(d.Children, result.Children)
+ d.From(result.GetSelf())
+ d.Children = make([]scheme.Entry, len(result.GetChildren()))
+ putEntry(d.Children, result.GetChildren())
+
return d, nil
}
func (c *Client) DescribePath(ctx context.Context, path string) (e scheme.Entry, finalErr error) {
onDone := trace.SchemeOnDescribePath(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).DescribePath"),
path,
)
defer func() {
@@ -184,10 +195,12 @@ func (c *Client) DescribePath(ctx context.Context, path string) (e scheme.Entry,
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
if !c.config.AutoRetry() {
err := call(ctx)
+
return e, err
}
err := retry.Retry(ctx, call,
@@ -195,6 +208,7 @@ func (c *Client) DescribePath(ctx context.Context, path string) (e scheme.Entry,
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
)
+
return e, xerrors.WithStackTrace(err)
}
@@ -222,7 +236,8 @@ func (c *Client) describePath(ctx context.Context, path string) (e scheme.Entry,
if err != nil {
return e, xerrors.WithStackTrace(err)
}
- e.From(result.Self)
+ e.From(result.GetSelf())
+
return e, nil
}
@@ -230,16 +245,16 @@ func (c *Client) ModifyPermissions(
ctx context.Context, path string, opts ...scheme.PermissionsOption,
) (finalErr error) {
onDone := trace.SchemeOnModifyPermissions(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).ModifyPermissions"),
path,
)
defer func() {
onDone(finalErr)
}()
var desc permissionsDesc
- for _, o := range opts {
- if o != nil {
- o(&desc)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&desc)
}
}
call := func(ctx context.Context) error {
@@ -248,6 +263,7 @@ func (c *Client) ModifyPermissions(
if !c.config.AutoRetry() {
return call(ctx)
}
+
return retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithIdempotent(true),
@@ -273,6 +289,7 @@ func (c *Client) modifyPermissions(ctx context.Context, path string, desc permis
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
diff --git a/internal/scheme/config/config.go b/internal/scheme/config/config.go
index ff3bd745a..a684fc83e 100644
--- a/internal/scheme/config/config.go
+++ b/internal/scheme/config/config.go
@@ -6,8 +6,6 @@ import (
)
// Config is a configuration of scheme client
-//
-//nolint:maligned
type Config struct {
config.Common
@@ -52,10 +50,11 @@ func New(opts ...Option) Config {
c := Config{
trace: &trace.Scheme{},
}
- for _, o := range opts {
- if o != nil {
- o(&c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&c)
}
}
+
return c
}
diff --git a/internal/scheme/helpers/check_exists.go b/internal/scheme/helpers/check_exists.go
index 2765ab9c7..534d12b36 100644
--- a/internal/scheme/helpers/check_exists.go
+++ b/internal/scheme/helpers/check_exists.go
@@ -50,8 +50,10 @@ func IsDirectoryExists(ctx context.Context, c schemeClient, directory string) (
childDirectory, parentDirectory, t.String(),
))
}
+
return true, nil
}
+
return false, nil
}
@@ -92,10 +94,12 @@ func IsEntryExists(ctx context.Context, c schemeClient, absPath string, entryTyp
return true, nil
}
}
+
return false, xerrors.WithStackTrace(fmt.Errorf(
"entry type of '%s' (%s) in path '%s' is not corresponds to %v",
entryName, childrenType, directory, entryTypes,
))
}
+
return false, nil
}
diff --git a/internal/scheme/helpers/check_exists_test.go b/internal/scheme/helpers/check_exists_test.go
index 8b3086f36..265346cae 100644
--- a/internal/scheme/helpers/check_exists_test.go
+++ b/internal/scheme/helpers/check_exists_test.go
@@ -33,6 +33,7 @@ func (c isDirectoryExistsSchemeClient) ListDirectory(ctx context.Context, path s
}
if strings.HasPrefix(c.existingPath, path) {
children := strings.Split(strings.TrimLeft(c.existingPath, path), "/")
+
return scheme.Directory{
Entry: scheme.Entry{
Name: path,
@@ -46,6 +47,7 @@ func (c isDirectoryExistsSchemeClient) ListDirectory(ctx context.Context, path s
},
}, nil
}
+
return d, fmt.Errorf("path '%s' not found in '%s'", path, c)
}
@@ -173,6 +175,7 @@ func (c isTableExistsSchemeClient) ListDirectory(ctx context.Context, path strin
}, nil
}
}
+
return d, fmt.Errorf("path '%s' not found in '%s'", path, c)
}
diff --git a/internal/scheme/options_test.go b/internal/scheme/options_test.go
index 5f99dfd32..b8ef769e9 100644
--- a/internal/scheme/options_test.go
+++ b/internal/scheme/options_test.go
@@ -28,9 +28,9 @@ func TestSchemeOptions(t *testing.T) {
}
var desc permissionsDesc
- for _, o := range opts {
- if o != nil {
- o(&desc)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&desc)
}
}
@@ -40,7 +40,7 @@ func TestSchemeOptions(t *testing.T) {
count := len(desc.actions)
for _, a := range desc.actions {
- switch a := a.Action.(type) {
+ switch a := a.GetAction().(type) {
case *Ydb_Scheme.PermissionsAction_ChangeOwner:
count--
if a.ChangeOwner != "ow" {
@@ -48,17 +48,19 @@ func TestSchemeOptions(t *testing.T) {
}
case *Ydb_Scheme.PermissionsAction_Grant:
count--
- if a.Grant.Subject != "grant" || len(a.Grant.PermissionNames) != 3 {
+ if a.Grant.GetSubject() != "grant" || len(a.Grant.GetPermissionNames()) != 3 {
t.Errorf("Grant is not as expected")
}
case *Ydb_Scheme.PermissionsAction_Set:
count--
- if a.Set.Subject != "set" || len(a.Set.PermissionNames) != 1 || a.Set.PermissionNames[0] != "d" {
+ if a.Set.GetSubject() != "set" || len(a.Set.GetPermissionNames()) != 1 || a.Set.GetPermissionNames()[0] != "d" {
t.Errorf("Set is not as expected")
}
case *Ydb_Scheme.PermissionsAction_Revoke:
count--
- if a.Revoke.Subject != "revoke" || len(a.Revoke.PermissionNames) != 1 || a.Revoke.PermissionNames[0] != "e" {
+ revokeSubject := a.Revoke.GetSubject()
+ permissionNames := a.Revoke.GetPermissionNames()
+ if revokeSubject != "revoke" || len(permissionNames) != 1 || permissionNames[0] != "e" {
t.Errorf("Revoke is not as expected")
}
}
diff --git a/internal/scripting/client.go b/internal/scripting/client.go
index b73f3c75f..a8ecc18bb 100644
--- a/internal/scripting/client.go
+++ b/internal/scripting/client.go
@@ -12,17 +12,17 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/scripting/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/scanner"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
"github.com/ydb-platform/ydb-go-sdk/v3/scripting"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
@@ -32,48 +32,53 @@ var (
errNilClient = xerrors.Wrap(errors.New("scripting client is not initialized"))
)
-type Client struct {
- config config.Config
- service Ydb_Scripting_V1.ScriptingServiceClient
-}
+type (
+ Client struct {
+ config config.Config
+ service Ydb_Scripting_V1.ScriptingServiceClient
+ }
+)
func (c *Client) Execute(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ parameters *params.Parameters,
) (r result.Result, err error) {
if c == nil {
return r, xerrors.WithStackTrace(errNilClient)
}
call := func(ctx context.Context) error {
- r, err = c.execute(ctx, query, params)
+ r, err = c.execute(ctx, query, parameters)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err = call(ctx)
+
return
}
err = retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
)
+
return r, xerrors.WithStackTrace(err)
}
func (c *Client) execute(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ parameters *params.Parameters,
) (r result.Result, err error) {
var (
onDone = trace.ScriptingOnExecute(c.config.Trace(), &ctx,
- stack.FunctionID(""),
- query, params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).execute"),
+ query, parameters,
)
a = allocator.New()
request = &Ydb_Scripting.ExecuteYqlRequest{
Script: query,
- Parameters: params.Params().ToYDB(a),
+ Parameters: parameters.ToYDB(a),
OperationParams: operation.Params(
ctx,
c.config.OperationTimeout(),
@@ -97,6 +102,7 @@ func (c *Client) execute(
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return scanner.NewUnary(result.GetResultSets(), result.GetQueryStats()), nil
}
@@ -121,10 +127,12 @@ func (c *Client) Explain(
}
call := func(ctx context.Context) error {
e, err = c.explain(ctx, query, mode)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err = call(ctx)
+
return
}
err = retry.Retry(ctx, call,
@@ -132,6 +140,7 @@ func (c *Client) Explain(
retry.WithIdempotent(true),
retry.WithTrace(c.config.TraceRetry()),
)
+
return e, xerrors.WithStackTrace(err)
}
@@ -142,7 +151,7 @@ func (c *Client) explain(
) (e table.ScriptingYQLExplanation, err error) {
var (
onDone = trace.ScriptingOnExplain(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).explain"),
query,
)
request = &Ydb_Scripting.ExplainYqlRequest{
@@ -177,48 +186,52 @@ func (c *Client) explain(
ParameterTypes: make(map[string]types.Type, len(result.GetParametersTypes())),
}
for k, v := range result.GetParametersTypes() {
- e.ParameterTypes[k] = value.TypeFromYDB(v)
+ e.ParameterTypes[k] = types.TypeFromYDB(v)
}
+
return e, nil
}
func (c *Client) StreamExecute(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ params *params.Parameters,
) (r result.StreamResult, err error) {
if c == nil {
return r, xerrors.WithStackTrace(errNilClient)
}
call := func(ctx context.Context) error {
r, err = c.streamExecute(ctx, query, params)
+
return xerrors.WithStackTrace(err)
}
if !c.config.AutoRetry() {
err = call(ctx)
+
return
}
err = retry.Retry(ctx, call,
retry.WithStackTrace(),
retry.WithTrace(c.config.TraceRetry()),
)
+
return r, xerrors.WithStackTrace(err)
}
func (c *Client) streamExecute(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ parameters *params.Parameters,
) (r result.StreamResult, err error) {
var (
onIntermediate = trace.ScriptingOnStreamExecute(c.config.Trace(), &ctx,
- stack.FunctionID(""),
- query, params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).streamExecute"),
+ query, parameters,
)
a = allocator.New()
request = &Ydb_Scripting.ExecuteYqlRequest{
Script: query,
- Parameters: params.Params().ToYDB(a),
+ Parameters: parameters.ToYDB(a),
OperationParams: operation.Params(
ctx,
c.config.OperationTimeout(),
@@ -239,6 +252,7 @@ func (c *Client) streamExecute(
stream, err := c.service.StreamExecuteYql(ctx, request)
if err != nil {
cancel()
+
return nil, xerrors.WithStackTrace(err)
}
@@ -261,12 +275,14 @@ func (c *Client) streamExecute(
if result == nil || err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
+
return result.GetResultSet(), result.GetQueryStats(), nil
}
},
func(err error) error {
cancel()
onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
+
return err
},
)
@@ -276,16 +292,19 @@ func (c *Client) Close(ctx context.Context) (err error) {
if c == nil {
return xerrors.WithStackTrace(errNilClient)
}
- onDone := trace.ScriptingOnClose(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.ScriptingOnClose(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).Close"),
+ )
defer func() {
onDone(err)
}()
+
return nil
}
-func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) (*Client, error) {
+func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) *Client {
return &Client{
config: config,
service: Ydb_Scripting_V1.NewScriptingServiceClient(cc),
- }, nil
+ }
}
diff --git a/internal/scripting/config/config.go b/internal/scripting/config/config.go
index 52fc846ae..35f90651d 100644
--- a/internal/scripting/config/config.go
+++ b/internal/scripting/config/config.go
@@ -36,10 +36,11 @@ func New(opts ...Option) Config {
c := Config{
trace: &trace.Scripting{},
}
- for _, o := range opts {
- if o != nil {
- o(&c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&c)
}
}
+
return c
}
diff --git a/internal/secret/password.go b/internal/secret/password.go
index 79a004984..2b6bdd1ba 100644
--- a/internal/secret/password.go
+++ b/internal/secret/password.go
@@ -19,5 +19,6 @@ func Password(password string) string {
bytes[i] = '*'
}
}
+
return xstring.FromBytes(bytes)
}
diff --git a/internal/secret/token.go b/internal/secret/token.go
index 70fab0eca..dc90e0c59 100644
--- a/internal/secret/token.go
+++ b/internal/secret/token.go
@@ -16,5 +16,6 @@ func Token(token string) string {
mask.WriteString("****")
}
mask.WriteString(fmt.Sprintf("(CRC-32c: %08X)", crc32.Checksum([]byte(token), crc32.IEEETable)))
+
return mask.String()
}
diff --git a/internal/session/status.go b/internal/session/status.go
new file mode 100644
index 000000000..49fbe7425
--- /dev/null
+++ b/internal/session/status.go
@@ -0,0 +1,12 @@
+package session
+
+type Status = string
+
+const (
+ StatusUnknown = Status("Unknown")
+ StatusIdle = Status("Idle")
+ StatusInUse = Status("InUse")
+ StatusClosing = Status("Closing")
+ StatusClosed = Status("Closed")
+ StatusError = Status("Error")
+)
diff --git a/internal/stack/function_id.go b/internal/stack/function_id.go
index 518551e5b..646a7f5ea 100644
--- a/internal/stack/function_id.go
+++ b/internal/stack/function_id.go
@@ -1,10 +1,10 @@
package stack
-type caller interface {
+type Caller interface {
FunctionID() string
}
-var _ caller = functionID("")
+var _ Caller = functionID("")
type functionID string
@@ -12,9 +12,10 @@ func (id functionID) FunctionID() string {
return string(id)
}
-func FunctionID(id string) caller {
+func FunctionID(id string) Caller {
if id != "" {
return functionID(id)
}
+
return Call(1)
}
diff --git a/internal/stack/function_id_test.go b/internal/stack/function_id_test.go
new file mode 100644
index 000000000..f1161fe3d
--- /dev/null
+++ b/internal/stack/function_id_test.go
@@ -0,0 +1,45 @@
+package stack
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+type genericType[T any] struct{}
+
+type starType struct{}
+
+func (t genericType[T]) Call() string {
+ return FunctionID("").FunctionID()
+}
+
+func staticCall() string {
+ return FunctionID("").FunctionID()
+}
+
+func (e *starType) starredCall() string {
+ return FunctionID("").FunctionID()
+}
+
+func TestFunctionIDForGenericType(t *testing.T) {
+ t.Run("StaticFunc", func(t *testing.T) {
+ require.Equal(t,
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.staticCall",
+ staticCall(),
+ )
+ })
+ t.Run("GenericTypeCall", func(t *testing.T) {
+ require.Equal(t,
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.genericType.Call",
+ genericType[uint64]{}.Call(),
+ )
+ })
+ t.Run("StarTypeCall", func(t *testing.T) {
+ x := starType{}
+ require.Equal(t,
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.(*starType).starredCall",
+ x.starredCall(),
+ )
+ })
+}
diff --git a/internal/stack/record.go b/internal/stack/record.go
index c47097a5c..efe5e9db6 100644
--- a/internal/stack/record.go
+++ b/internal/stack/record.go
@@ -62,7 +62,7 @@ func PackagePath(b bool) recordOption {
}
}
-var _ caller = call{}
+var _ Caller = call{}
type call struct {
function uintptr
@@ -72,6 +72,7 @@ type call struct {
func Call(depth int) (c call) {
c.function, c.file, c.line, _ = runtime.Caller(depth + 1)
+
return c
}
@@ -86,7 +87,9 @@ func (c call) Record(opts ...recordOption) string {
lambdas: true,
}
for _, opt := range opts {
- opt(&optionsHolder)
+ if opt != nil {
+ opt(&optionsHolder)
+ }
}
name := runtime.FuncForPC(c.function).Name()
var (
@@ -102,6 +105,7 @@ func (c call) Record(opts ...recordOption) string {
if i := strings.LastIndex(name, "/"); i > -1 {
pkgPath, name = name[:i], name[i+1:]
}
+ name = strings.ReplaceAll(name, "[...]", "")
split := strings.Split(name, ".")
lambdas := make([]string, 0, len(split))
for i := range split {
@@ -166,6 +170,7 @@ func (c call) Record(opts ...recordOption) string {
buffer.WriteByte(')')
}
}
+
return buffer.String()
}
diff --git a/internal/table/client.go b/internal/table/client.go
index 1a3fceeeb..20dd9cb6e 100644
--- a/internal/table/client.go
+++ b/internal/table/client.go
@@ -34,7 +34,14 @@ type balancer interface {
nodeChecker
}
-func New(ctx context.Context, balancer balancer, config *config.Config) (*Client, error) {
+func New(ctx context.Context, balancer balancer, config *config.Config) *Client {
+ onDone := trace.TableOnInit(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.New"),
+ )
+ defer func() {
+ onDone(config.SizeLimit())
+ }()
+
return newClient(ctx, balancer, func(ctx context.Context) (s *session, err error) {
return newSession(ctx, balancer, config)
}, config)
@@ -45,12 +52,8 @@ func newClient(
balancer balancer,
builder sessionBuilder,
config *config.Config,
-) (c *Client, finalErr error) {
- onDone := trace.TableOnInit(config.Trace(), &ctx, stack.FunctionID(""))
- defer func() {
- onDone(config.SizeLimit(), finalErr)
- }()
- c = &Client{
+) *Client {
+ c := &Client{
clock: config.Clock(),
config: config,
cc: balancer,
@@ -63,6 +66,7 @@ func newClient(
waitChPool: sync.Pool{
New: func() interface{} {
ch := make(chan *session)
+
return &ch
},
},
@@ -73,7 +77,7 @@ func newClient(
go c.internalPoolGC(ctx, idleThreshold)
}
- return c, nil
+ return c
}
// Client is a set of session instances that may be reused.
@@ -120,9 +124,9 @@ func withCreateSessionOnClose(onClose func(s *session)) createSessionOption {
func (c *Client) createSession(ctx context.Context, opts ...createSessionOption) (s *session, err error) {
options := createSessionOptions{}
- for _, o := range opts {
- if o != nil {
- o(&options)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&options)
}
}
@@ -164,7 +168,7 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
err error
)
- createSessionCtx := xcontext.WithoutDeadline(ctx)
+ createSessionCtx := xcontext.ValueOnly(ctx)
if timeout := c.config.CreateSessionTimeout(); timeout > 0 {
var cancel context.CancelFunc
@@ -177,7 +181,7 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
return
}
- closeSessionCtx := xcontext.WithoutDeadline(ctx)
+ closeSessionCtx := xcontext.ValueOnly(ctx)
if timeout := c.config.DeleteTimeout(); timeout > 0 {
var cancel context.CancelFunc
@@ -217,6 +221,7 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
if r.err != nil {
return nil, xerrors.WithStackTrace(r.err)
}
+
return r.s, nil
}
}
@@ -234,6 +239,7 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return s, nil
}
if !c.config.AutoRetry() {
@@ -241,6 +247,7 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return s, nil
}
err = retry.Retry(ctx,
@@ -249,25 +256,27 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
},
append(
[]retry.Option{
retry.WithIdempotent(true),
retry.WithTrace(&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- onIntermediate := trace.TableOnCreateSession(c.config.Trace(), info.Context, stack.FunctionID(""))
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- onDone := onIntermediate(info.Error)
- return func(info trace.RetryLoopDoneInfo) {
- onDone(s, info.Attempts, info.Error)
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ onDone := trace.TableOnCreateSession(c.config.Trace(), info.Context,
+ stack.FunctionID(
+ "github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).CreateSession"))
+
+ return func(info trace.RetryLoopDoneInfo) {
+ onDone(s, info.Attempts, info.Error)
}
},
}),
}, c.retryOptions(opts...).RetryOptions...,
)...,
)
+
return s, xerrors.WithStackTrace(err)
}
@@ -372,7 +381,9 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
}
}
- onDone := trace.TableOnPoolGet(o.t, &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnPoolGet(o.t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).internalPoolGet"),
+ )
defer func() {
onDone(s, i, err)
}()
@@ -389,6 +400,7 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
if c.nodeChecker != nil && !c.nodeChecker.HasNode(s.NodeID()) {
_ = s.Close(ctx)
s = nil
+
continue
}
@@ -437,6 +449,7 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
idle = c.idle.Len()
createInProgress = c.createInProgress
})
+
return s, xerrors.WithStackTrace(
fmt.Errorf("failed to get session from pool ("+
"attempts: %d, latency: %v, pool have %d sessions (%d busy, %d idle, %d create_in_progress): %w",
@@ -444,6 +457,7 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
),
)
}
+
return s, nil
}
@@ -465,7 +479,9 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
el = c.waitQ.PushBack(ch)
})
- waitDone := trace.TableOnPoolWait(t, &ctx, stack.FunctionID(""))
+ waitDone := trace.TableOnPoolWait(t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).internalPoolWaitFromCh"),
+ )
defer func() {
waitDone(s, err)
@@ -481,6 +497,7 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
c.mu.WithLock(func() {
c.waitQ.Remove(el)
})
+
return nil, xerrors.WithStackTrace(errClosedClient)
case s, ok = <-*ch:
@@ -496,18 +513,21 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
// for the next waiter – session could be lost for a long time.
c.internalPoolPutWaitCh(ch)
}
+
return s, nil
case <-createSessionTimeoutCh:
c.mu.WithLock(func() {
c.waitQ.Remove(el)
})
+
return nil, nil //nolint:nilnil
case <-ctx.Done():
c.mu.WithLock(func() {
c.waitQ.Remove(el)
})
+
return nil, xerrors.WithStackTrace(ctx.Err())
}
}
@@ -523,7 +543,7 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
// panic.
func (c *Client) Put(ctx context.Context, s *session) (err error) {
onDone := trace.TableOnPoolPut(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).Put"),
s,
)
defer func() {
@@ -582,7 +602,9 @@ func (c *Client) Close(ctx context.Context) (err error) {
default:
close(c.done)
- onDone := trace.TableOnClose(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnClose(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).Close"),
+ )
defer func() {
onDone(err)
}()
@@ -627,17 +649,16 @@ func (c *Client) Do(ctx context.Context, op table.Operation, opts ...table.Optio
config := c.retryOptions(opts...)
- attempts, onIntermediate := 0, trace.TableOnDo(config.Trace, &ctx,
- stack.FunctionID(""),
- config.Label, config.Label, config.Idempotent, xcontext.IsNestedCall(ctx),
+ attempts, onDone := 0, trace.TableOnDo(config.Trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).Do"),
+ config.Label, config.Idempotent, xcontext.IsNestedCall(ctx),
)
defer func() {
- onIntermediate(finalErr)(attempts, finalErr)
+ onDone(attempts, finalErr)
}()
err := do(ctx, c, c.config, op, func(err error) {
attempts++
- onIntermediate(err)
}, config.RetryOptions...)
if err != nil {
return xerrors.WithStackTrace(err)
@@ -657,22 +678,18 @@ func (c *Client) DoTx(ctx context.Context, op table.TxOperation, opts ...table.O
config := c.retryOptions(opts...)
- attempts, onIntermediate := 0, trace.TableOnDoTx(config.Trace, &ctx,
- stack.FunctionID(""),
- config.Label, config.Label, config.Idempotent, xcontext.IsNestedCall(ctx),
+ attempts, onDone := 0, trace.TableOnDoTx(config.Trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).DoTx"),
+ config.Label, config.Idempotent, xcontext.IsNestedCall(ctx),
)
defer func() {
- onIntermediate(finalErr)(attempts, finalErr)
+ onDone(attempts, finalErr)
}()
return retryBackoff(ctx, c,
func(ctx context.Context, s table.Session) (err error) {
attempts++
- defer func() {
- onIntermediate(err)
- }()
-
tx, err := s.BeginTransaction(ctx, config.TxSettings)
if err != nil {
return xerrors.WithStackTrace(err)
@@ -700,6 +717,7 @@ func (c *Client) DoTx(ctx context.Context, op table.TxOperation, opts ...table.O
}
}()
}
+
return op(xcontext.MarkRetryCall(ctx), tx)
}()
@@ -779,6 +797,7 @@ func (c *Client) internalPoolGetWaitCh() *chan *session { //nolint:gocritic
if !ok {
panic(fmt.Sprintf("%T is not a chan of sessions", ch))
}
+
return s
}
@@ -801,6 +820,7 @@ func (c *Client) internalPoolPeekFirstIdle() (s *session, touched time.Time) {
if !has || el != info.idle {
panic("inconsistent session client index")
}
+
return s, info.touched
}
@@ -814,6 +834,7 @@ func (c *Client) internalPoolRemoveFirstIdle() *session {
info := c.internalPoolRemoveIdle(s)
c.index[s] = info
}
+
return s
}
@@ -848,6 +869,7 @@ func (c *Client) internalPoolNotify(s *session) (notified bool) {
close(*ch)
}
}
+
return false
}
@@ -869,6 +891,7 @@ func (c *Client) internalPoolRemoveIdle(s *session) sessionInfo {
c.idle.Remove(info.idle)
info.idle = nil
c.index[s] = info
+
return info
}
diff --git a/internal/table/client_test.go b/internal/table/client_test.go
index 90937d41c..82b7eb6af 100644
--- a/internal/table/client_test.go
+++ b/internal/table/client_test.go
@@ -8,6 +8,7 @@ import (
"path"
"runtime"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -18,8 +19,8 @@ import (
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/emptypb"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xrand"
@@ -122,6 +123,7 @@ func TestSessionPoolCloseWhenWaiting(t *testing.T) {
&trace.Table{
OnPoolWait: func(trace.TablePoolWaitStartInfo) func(trace.TablePoolWaitDoneInfo) {
wait <- struct{}{}
+
return nil
},
},
@@ -139,6 +141,7 @@ func TestSessionPoolCloseWhenWaiting(t *testing.T) {
withTrace(&trace.Table{
OnPoolGet: func(trace.TablePoolGetStartInfo) func(trace.TablePoolGetDoneInfo) {
get <- struct{}{}
+
return nil
},
}),
@@ -346,10 +349,12 @@ func TestSessionPoolDeleteReleaseWait(t *testing.T) {
&trace.Table{
OnPoolGet: func(trace.TablePoolGetStartInfo) func(trace.TablePoolGetDoneInfo) {
get <- struct{}{}
+
return nil
},
OnPoolWait: func(trace.TablePoolWaitStartInfo) func(trace.TablePoolWaitDoneInfo) {
wait <- struct{}{}
+
return nil
},
},
@@ -403,7 +408,7 @@ func TestSessionPoolRacyGet(t *testing.T) {
session *session
}
create := make(chan createReq)
- p, err := newClient(
+ p := newClient(
context.Background(),
nil,
(&StubBuilder{
@@ -415,6 +420,7 @@ func TestSessionPoolRacyGet(t *testing.T) {
}
create <- req
<-req.release
+
return req.session, nil
},
}).createSession,
@@ -423,10 +429,10 @@ func TestSessionPoolRacyGet(t *testing.T) {
config.WithIdleThreshold(-1),
),
)
- require.NoError(t, err)
var (
expSession *session
done = make(chan struct{}, 2)
+ err error
)
for i := 0; i < 2; i++ {
go func() {
@@ -436,10 +442,12 @@ func TestSessionPoolRacyGet(t *testing.T) {
s, e := p.Get(context.Background())
if e != nil {
err = e
+
return
}
if s != expSession {
err = fmt.Errorf("unexpected session: %v; want %v", s, expSession)
+
return
}
mustPutSession(t, p, s)
@@ -553,10 +561,12 @@ func TestSessionPoolSizeLimitOverflow(t *testing.T) {
withTrace(&trace.Table{
OnPoolGet: func(trace.TablePoolGetStartInfo) func(trace.TablePoolGetDoneInfo) {
get <- struct{}{}
+
return nil
},
OnPoolWait: func(trace.TablePoolWaitStartInfo) func(trace.TablePoolWaitDoneInfo) {
wait <- struct{}{}
+
return nil
},
}),
@@ -628,12 +638,14 @@ func TestSessionPoolGetPut(t *testing.T) {
testutil.InvokeHandlers{
testutil.TableCreateSession: func(interface{}) (proto.Message, error) {
created++
+
return &Ydb_Table.CreateSessionResult{
SessionId: testutil.SessionID(),
}, nil
},
testutil.TableDeleteSession: func(interface{}) (proto.Message, error) {
deleted++
+
return nil, nil
},
},
@@ -666,7 +678,7 @@ func TestSessionPoolCloseIdleSessions(t *testing.T) {
xtest.TestManyTimes(t, func(t testing.TB) {
var (
idleThreshold = 4 * time.Second
- closedCount xatomic.Int64
+ closedCount atomic.Int64
fakeClock = clockwork.NewFakeClock()
)
p := newClientWithStubBuilder(
@@ -677,6 +689,7 @@ func TestSessionPoolCloseIdleSessions(t *testing.T) {
testutil.TableDeleteSession: okHandler,
testutil.TableCreateSession: func(interface{}) (proto.Message, error) {
closedCount.Add(1)
+
return &Ydb_Table.CreateSessionResult{
SessionId: testutil.SessionID(),
}, nil
@@ -757,6 +770,7 @@ func mustGetSession(t testing.TB, p *Client) *session {
t.Helper()
t.Fatalf("%s: %v", caller(), err)
}
+
return s
}
@@ -769,7 +783,7 @@ func mustPutSession(t testing.TB, p *Client, s *session) {
}
}
-func mustClose(t testing.TB, p *Client) {
+func mustClose(t testing.TB, p closer.Closer) {
wg := sync.WaitGroup{}
defer wg.Wait()
if err := p.Close(context.Background()); err != nil {
@@ -780,6 +794,7 @@ func mustClose(t testing.TB, p *Client) {
func caller() string {
_, file, line, _ := runtime.Caller(2)
+
return fmt.Sprintf("%s:%d", path.Base(file), line)
}
@@ -836,6 +851,7 @@ func simpleSession(t *testing.T) *session {
if err != nil {
t.Fatalf("newSession unexpected error: %v", err)
}
+
return s
}
@@ -856,7 +872,7 @@ func newClientWithStubBuilder(
stubLimit int,
options ...config.Option,
) *Client {
- c, err := newClient(
+ c := newClient(
context.Background(),
balancer,
(&StubBuilder{
@@ -866,7 +882,7 @@ func newClientWithStubBuilder(
}).createSession,
config.New(options...),
)
- require.NoError(t, err)
+
return c
}
@@ -912,6 +928,7 @@ func whenWantWaitCh(p *Client) <-chan struct{} {
p.testHookGetWaitCh = prev
close(ch)
}
+
return ch
}
@@ -932,6 +949,7 @@ func TestDeadlockOnUpdateNodes(t *testing.T) {
return nil, err
}
nodes = append(nodes, nodeID)
+
return &Ydb_Table.CreateSessionResult{
SessionId: sessionID,
}, nil
@@ -974,6 +992,7 @@ func TestDeadlockOnInternalPoolGCTick(t *testing.T) {
return nil, err
}
nodes = append(nodes, nodeID)
+
return &Ydb_Table.CreateSessionResult{
SessionId: sessionID,
}, nil
diff --git a/internal/table/config/config.go b/internal/table/config/config.go
index 6b8540f81..de94fb3e6 100644
--- a/internal/table/config/config.go
+++ b/internal/table/config/config.go
@@ -27,11 +27,12 @@ const (
func New(opts ...Option) *Config {
c := defaults()
- for _, o := range opts {
- if o != nil {
- o(c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(c)
}
}
+
return c
}
diff --git a/internal/table/data_query.go b/internal/table/data_query.go
index c5063a30e..f918b7192 100644
--- a/internal/table/data_query.go
+++ b/internal/table/data_query.go
@@ -36,6 +36,7 @@ func (q textDataQuery) YQL() string {
func (q textDataQuery) toYDB(a *allocator.Allocator) *Ydb_Table.Query {
query := a.TableQuery()
query.Query = a.TableQueryYqlText(string(q))
+
return query
}
@@ -54,6 +55,7 @@ func (q preparedDataQuery) YQL() string {
func (q preparedDataQuery) toYDB(a *allocator.Allocator) *Ydb_Table.Query {
query := a.TableQuery()
query.Query = a.TableQueryID(q.id)
+
return query
}
diff --git a/internal/table/params.go b/internal/table/params.go
deleted file mode 100644
index a4efeee38..000000000
--- a/internal/table/params.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package table
-
-import (
- "bytes"
- "fmt"
- "sort"
-
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
- "github.com/ydb-platform/ydb-go-sdk/v3/table"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
-)
-
-var ErrNameRequired = xerrors.Wrap(fmt.Errorf("only named parameters are supported"))
-
-// GenerateDeclareSection generates DECLARE section text in YQL query by params
-//
-// Warning: This is an experimental feature and could change at any time
-func GenerateDeclareSection(params *table.QueryParameters) (string, error) {
- var (
- buf bytes.Buffer
- names []string
- declares = make(map[string]string, len(params.Params()))
- )
- params.Each(func(name string, v types.Value) {
- names = append(names, name)
- declares[name] = fmt.Sprintf(
- "DECLARE %s AS %s;\n",
- name,
- v.Type().Yql(),
- )
- })
- sort.Strings(names)
- for _, name := range names {
- if name == "" {
- return "", xerrors.WithStackTrace(ErrNameRequired)
- }
- buf.WriteString(declares[name])
- }
- return buf.String(), nil
-}
diff --git a/internal/table/retry.go b/internal/table/retry.go
index d04408094..d6577d7ad 100644
--- a/internal/table/retry.go
+++ b/internal/table/retry.go
@@ -46,6 +46,7 @@ func do(
}
}()
}
+
return op(xcontext.MarkRetryCall(ctx), s)
}()
@@ -80,6 +81,7 @@ func retryBackoff(
if err = op(ctx, s); err != nil {
s.checkError(err)
+
return xerrors.WithStackTrace(err)
}
@@ -107,5 +109,6 @@ func (c *Client) retryOptions(opts ...table.Option) *table.Options {
if options.Trace == nil {
options.Trace = &trace.Table{}
}
+
return options
}
diff --git a/internal/table/retry_test.go b/internal/table/retry_test.go
index 43a1c865e..008633786 100644
--- a/internal/table/retry_test.go
+++ b/internal/table/retry_test.go
@@ -51,6 +51,7 @@ func TestRetryerBackoffRetryCancelation(t *testing.T) {
testutil.BackoffFunc(func(n int) <-chan time.Time {
ch := make(chan time.Time)
backoff <- ch
+
return ch
}),
),
@@ -58,6 +59,7 @@ func TestRetryerBackoffRetryCancelation(t *testing.T) {
testutil.BackoffFunc(func(n int) <-chan time.Time {
ch := make(chan time.Time)
backoff <- ch
+
return ch
}),
),
@@ -84,12 +86,14 @@ func TestRetryerBadSession(t *testing.T) {
s.onClose = append(s.onClose, func(s *session) {
closed[s] = true
})
+
return s, nil
},
OnPut: func(ctx context.Context, s *session) error {
if s.isClosing() {
return s.Close(ctx)
}
+
return nil
},
}
@@ -106,6 +110,7 @@ func TestRetryerBadSession(t *testing.T) {
if i > maxRetryes {
cancel()
}
+
return xerrors.Operation(
xerrors.WithStatusCode(Ydb.StatusIds_BAD_SESSION),
)
@@ -136,12 +141,14 @@ func TestRetryerSessionClosing(t *testing.T) {
s.onClose = append(s.onClose, func(s *session) {
closed[s] = true
})
+
return s, nil
},
OnPut: func(ctx context.Context, s *session) error {
if s.isClosing() {
return s.Close(ctx)
}
+
return nil
},
}
@@ -154,6 +161,7 @@ func TestRetryerSessionClosing(t *testing.T) {
func(ctx context.Context, s table.Session) error {
sessions = append(sessions, s)
s.(*session).SetStatus(table.SessionClosing)
+
return nil
},
nil,
@@ -444,6 +452,7 @@ func TestRetryWithCustomErrors(t *testing.T) {
if i < limit {
return test.error
}
+
return nil
},
nil,
@@ -486,6 +495,7 @@ func (f SessionProviderFunc) Get(ctx context.Context) (*session, error) {
if f.OnGet == nil {
return nil, xerrors.WithStackTrace(errNoSession)
}
+
return f.OnGet(ctx)
}
@@ -493,6 +503,7 @@ func (f SessionProviderFunc) Put(ctx context.Context, s *session) error {
if f.OnPut == nil {
return xerrors.WithStackTrace(testutil.ErrNotImplemented)
}
+
return f.OnPut(ctx, s)
}
@@ -512,6 +523,7 @@ func (s *singleSession) Get(context.Context) (*session, error) {
return nil, xerrors.WithStackTrace(errNoSession)
}
s.empty = true
+
return s.s, nil
}
@@ -523,6 +535,7 @@ func (s *singleSession) Put(_ context.Context, x *session) error {
return xerrors.WithStackTrace(errSessionOverflow)
}
s.empty = false
+
return nil
}
diff --git a/internal/table/scanner/result.go b/internal/table/scanner/result.go
index e620e19bd..1cbc88eb6 100644
--- a/internal/table/scanner/result.go
+++ b/internal/table/scanner/result.go
@@ -4,11 +4,11 @@ import (
"context"
"errors"
"io"
+ "sync/atomic"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_TableStats"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
@@ -18,13 +18,13 @@ import (
var errAlreadyClosed = xerrors.Wrap(errors.New("result closed early"))
type baseResult struct {
- scanner
+ valueScanner
- nextResultSetCounter xatomic.Uint64
+ nextResultSetCounter atomic.Uint64
statsMtx xsync.RWMutex
stats *Ydb_TableStats.QueryStats
- closed xatomic.Bool
+ closed atomic.Bool
}
type streamResult struct {
@@ -36,10 +36,11 @@ type streamResult struct {
// Err returns error caused Scanner to be broken.
func (r *streamResult) Err() error {
- err := r.scanner.Err()
+ err := r.valueScanner.Err()
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -52,10 +53,11 @@ type unaryResult struct {
// Err returns error caused Scanner to be broken.
func (r *unaryResult) Err() error {
- err := r.scanner.Err()
+ err := r.valueScanner.Err()
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -64,6 +66,7 @@ func (r *unaryResult) Close() error {
if r.closed.CompareAndSwap(false, true) {
return nil
}
+
return xerrors.WithStackTrace(errAlreadyClosed)
}
@@ -93,13 +96,13 @@ type option func(r *baseResult)
func WithIgnoreTruncated(ignoreTruncated bool) option {
return func(r *baseResult) {
- r.scanner.ignoreTruncated = ignoreTruncated
+ r.valueScanner.ignoreTruncated = ignoreTruncated
}
}
func WithMarkTruncatedAsRetryable() option {
return func(r *baseResult) {
- r.scanner.markTruncatedAsRetryable = true
+ r.valueScanner.markTruncatedAsRetryable = true
}
}
@@ -113,14 +116,15 @@ func NewStream(
recv: recv,
close: onClose,
}
- for _, o := range opts {
- if o != nil {
- o(&r.baseResult)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&r.baseResult)
}
}
if err := r.nextResultSetErr(ctx); err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return r, nil
}
@@ -131,11 +135,12 @@ func NewUnary(sets []*Ydb.ResultSet, stats *Ydb_TableStats.QueryStats, opts ...o
},
sets: sets,
}
- for _, o := range opts {
- if o != nil {
- o(&r.baseResult)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&r.baseResult)
}
}
+
return r
}
@@ -155,6 +160,7 @@ func (r *unaryResult) NextResultSetErr(ctx context.Context, columns ...string) (
}
r.Reset(r.sets[r.nextSet], columns...)
r.nextSet++
+
return ctx.Err()
}
@@ -166,6 +172,7 @@ func (r *streamResult) nextResultSetErr(ctx context.Context, columns ...string)
// skipping second recv because first call of recv is from New Stream(), second call is from user
if r.nextResultSetCounter.Add(1) == 2 {
r.setColumnIndexes(columns)
+
return ctx.Err()
}
s, stats, err := r.recv(ctx)
@@ -174,6 +181,7 @@ func (r *streamResult) nextResultSetErr(ctx context.Context, columns ...string)
if xerrors.Is(err, io.EOF) {
return err
}
+
return r.errorf(1, "streamResult.NextResultSetErr(): %w", err)
}
r.Reset(s, columns...)
@@ -182,6 +190,7 @@ func (r *streamResult) nextResultSetErr(ctx context.Context, columns ...string)
r.stats = stats
})
}
+
return ctx.Err()
}
@@ -196,8 +205,10 @@ func (r *streamResult) NextResultSetErr(ctx context.Context, columns ...string)
if xerrors.Is(err, io.EOF) {
return io.EOF
}
+
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -229,6 +240,7 @@ func (r *streamResult) Close() (err error) {
if r.closed.CompareAndSwap(false, true) {
return r.close(r.Err())
}
+
return xerrors.WithStackTrace(errAlreadyClosed)
}
@@ -252,5 +264,6 @@ func (r *unaryResult) HasNextResultSet() bool {
if r.inactive() || r.nextSet >= len(r.sets) {
return false
}
+
return true
}
diff --git a/internal/table/scanner/result_test.go b/internal/table/scanner/result_test.go
index e7eb25e36..dc81b0203 100644
--- a/internal/table/scanner/result_test.go
+++ b/internal/table/scanner/result_test.go
@@ -13,29 +13,29 @@ import (
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_TableStats"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
func TestResultAny(t *testing.T) {
for _, test := range []struct {
name string
columns []options.Column
- values []types.Value
+ values []value.Value
exp []interface{}
}{
{
columns: []options.Column{
{
Name: "column0",
- Type: types.Optional(types.TypeUint32),
+ Type: types.NewOptional(types.Uint32),
Family: "family0",
},
},
- values: []types.Value{
- types.OptionalValue(types.Uint32Value(43)),
- types.NullValue(types.TypeUint32),
+ values: []value.Value{
+ value.OptionalValue(value.Uint32Value(43)),
+ value.NullValue(types.Uint32),
},
exp: []interface{}{
uint32(43),
@@ -83,25 +83,25 @@ func TestResultOUint32(t *testing.T) {
for _, test := range []struct {
name string
columns []options.Column
- values []types.Value
+ values []value.Value
exp []uint32
}{
{
columns: []options.Column{
{
Name: "column0",
- Type: types.Optional(types.TypeUint32),
+ Type: types.NewOptional(types.Uint32),
Family: "family0",
},
{
Name: "column1",
- Type: types.TypeUint32,
+ Type: types.Uint32,
Family: "family0",
},
},
- values: []types.Value{
- types.OptionalValue(types.Uint32Value(43)),
- types.Uint32Value(43),
+ values: []value.Value{
+ value.OptionalValue(value.Uint32Value(43)),
+ value.Uint32Value(43),
},
exp: []uint32{
43,
@@ -151,13 +151,13 @@ func WithColumns(cs ...options.Column) ResultSetOption {
for _, c := range cs {
r.Columns = append(r.Columns, &Ydb.Column{
Name: c.Name,
- Type: value.TypeToYDB(c.Type, a),
+ Type: types.TypeToYDB(c.Type, a),
})
}
}
}
-func WithValues(vs ...types.Value) ResultSetOption {
+func WithValues(vs ...value.Value) ResultSetOption {
return func(r *resultSetDesc, a *allocator.Allocator) {
n := len(r.Columns)
if n == 0 {
@@ -178,15 +178,15 @@ func WithValues(vs ...types.Value) ResultSetOption {
}
}
tv := value.ToYDB(v, a)
- act := value.TypeFromYDB(tv.Type)
- exp := value.TypeFromYDB(r.Columns[j].Type)
- if !value.TypesEqual(act, exp) {
+ act := types.TypeFromYDB(tv.GetType())
+ exp := types.TypeFromYDB(r.Columns[j].GetType())
+ if !types.Equal(act, exp) {
panic(fmt.Sprintf(
"unexpected types for #%d column: %s; want %s",
j, act, exp,
))
}
- row.Items[j] = tv.Value
+ row.Items[j] = tv.GetValue()
}
if row != nil {
r.Rows = append(r.Rows, row)
@@ -201,6 +201,7 @@ func NewResultSet(a *allocator.Allocator, opts ...ResultSetOption) *Ydb.ResultSe
opt(&d, a)
}
}
+
return (*Ydb.ResultSet)(&d)
}
@@ -218,6 +219,7 @@ func TestNewStreamWithRecvFirstResultSet(t *testing.T) {
ctx: func() context.Context {
ctx, cancel := context.WithCancel(context.Background())
cancel()
+
return ctx
}(),
err: context.Canceled,
@@ -226,6 +228,7 @@ func TestNewStreamWithRecvFirstResultSet(t *testing.T) {
ctx: func() context.Context {
ctx, cancel := context.WithTimeout(context.Background(), 0)
cancel()
+
return ctx
}(),
err: context.DeadlineExceeded,
@@ -234,6 +237,7 @@ func TestNewStreamWithRecvFirstResultSet(t *testing.T) {
ctx: func() context.Context {
ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
cancel()
+
return ctx
}(),
err: context.Canceled,
@@ -246,6 +250,7 @@ func TestNewStreamWithRecvFirstResultSet(t *testing.T) {
if tt.recvCounter > 1000 {
return nil, nil, io.EOF
}
+
return &Ydb.ResultSet{}, nil, ctx.Err()
},
func(err error) error {
diff --git a/internal/table/scanner/scan_raw.go b/internal/table/scanner/scan_raw.go
index b9e7732d9..7c0782f3c 100644
--- a/internal/table/scanner/scan_raw.go
+++ b/internal/table/scanner/scan_raw.go
@@ -10,18 +10,20 @@ import (
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/decimal"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
type rawConverter struct {
- *scanner
+ *valueScanner
}
func (s *rawConverter) String() (v []byte) {
s.unwrap()
+
return s.bytes()
}
@@ -30,12 +32,13 @@ func (s *rawConverter) HasItems() bool {
}
func (s *rawConverter) HasNextItem() bool {
- return s.hasItems() && s.nextItem < len(s.row.Items)
+ return s.hasItems() && s.nextItem < len(s.row.GetItems())
}
func (s *rawConverter) Path() string {
var buf bytes.Buffer
_, _ = s.WritePathTo(&buf)
+
return buf.String()
}
@@ -61,6 +64,7 @@ func (s *rawConverter) WritePathTo(w io.Writer) (n int64, err error) {
}
n += int64(m)
}
+
return n, nil
}
@@ -73,6 +77,7 @@ func (s *rawConverter) Bool() (v bool) {
return
}
s.unwrap()
+
return s.bool()
}
@@ -81,6 +86,7 @@ func (s *rawConverter) Int8() (v int8) {
return
}
s.unwrap()
+
return s.int8()
}
@@ -89,6 +95,7 @@ func (s *rawConverter) Uint8() (v uint8) {
return
}
s.unwrap()
+
return s.uint8()
}
@@ -97,6 +104,7 @@ func (s *rawConverter) Int16() (v int16) {
return
}
s.unwrap()
+
return s.int16()
}
@@ -105,6 +113,7 @@ func (s *rawConverter) Uint16() (v uint16) {
return
}
s.unwrap()
+
return s.uint16()
}
@@ -113,6 +122,7 @@ func (s *rawConverter) Int32() (v int32) {
return
}
s.unwrap()
+
return s.int32()
}
@@ -121,6 +131,7 @@ func (s *rawConverter) Uint32() (v uint32) {
return
}
s.unwrap()
+
return s.uint32()
}
@@ -129,6 +140,7 @@ func (s *rawConverter) Int64() (v int64) {
return
}
s.unwrap()
+
return s.int64()
}
@@ -137,6 +149,7 @@ func (s *rawConverter) Uint64() (v uint64) {
return
}
s.unwrap()
+
return s.uint64()
}
@@ -145,6 +158,7 @@ func (s *rawConverter) Float() (v float32) {
return
}
s.unwrap()
+
return s.float()
}
@@ -153,26 +167,31 @@ func (s *rawConverter) Double() (v float64) {
return
}
s.unwrap()
+
return s.double()
}
func (s *rawConverter) Date() (v time.Time) {
s.unwrap()
+
return value.DateToTime(s.uint32())
}
func (s *rawConverter) Datetime() (v time.Time) {
s.unwrap()
+
return value.DatetimeToTime(s.uint32())
}
func (s *rawConverter) Timestamp() (v time.Time) {
s.unwrap()
+
return value.TimestampToTime(s.uint64())
}
func (s *rawConverter) Interval() (v time.Duration) {
s.unwrap()
+
return value.IntervalToDuration(s.int64())
}
@@ -185,6 +204,7 @@ func (s *rawConverter) TzDate() (v time.Time) {
if err != nil {
_ = s.errorf(0, "rawConverter.TzDate(): %w", err)
}
+
return src
}
@@ -197,6 +217,7 @@ func (s *rawConverter) TzDatetime() (v time.Time) {
if err != nil {
_ = s.errorf(0, "rawConverter.TzDatetime(): %w", err)
}
+
return src
}
@@ -209,6 +230,7 @@ func (s *rawConverter) TzTimestamp() (v time.Time) {
if err != nil {
_ = s.errorf(0, "rawConverter.TzTimestamp(): %w", err)
}
+
return src
}
@@ -217,21 +239,25 @@ func (s *rawConverter) UTF8() (v string) {
return
}
s.unwrap()
+
return s.text()
}
func (s *rawConverter) YSON() (v []byte) {
s.unwrap()
+
return s.bytes()
}
func (s *rawConverter) JSON() (v []byte) {
s.unwrap()
+
return xstring.ToBytes(s.text())
}
func (s *rawConverter) JSONDocument() (v []byte) {
s.unwrap()
+
return xstring.ToBytes(s.text())
}
@@ -240,6 +266,7 @@ func (s *rawConverter) UUID() (v [16]byte) {
return
}
s.unwrap()
+
return s.uint128()
}
@@ -248,6 +275,7 @@ func (s *rawConverter) DyNumber() (v string) {
return
}
s.unwrap()
+
return s.text()
}
@@ -255,12 +283,13 @@ func (s *rawConverter) Any() interface{} {
return s.any()
}
-// Value returns current item under scan as ydb.Value types.
-func (s *rawConverter) Value() types.Value {
+// Value returns current item under scan as value
+func (s *rawConverter) Value() value.Value {
if s.Err() != nil {
return nil
}
s.unwrap()
+
return s.value()
}
@@ -279,6 +308,7 @@ func (s *rawConverter) IsNull() bool {
if s.Err() != nil {
return false
}
+
return s.isNull()
}
@@ -286,6 +316,7 @@ func (s *rawConverter) IsOptional() bool {
if s.Err() != nil {
return false
}
+
return s.isCurrentTypeOptional()
}
@@ -299,6 +330,7 @@ func (s *rawConverter) ListIn() (size int) {
if s.assertTypeList(x.t) != nil {
return s.itemsIn()
}
+
return 0
}
@@ -307,14 +339,14 @@ func (s *rawConverter) ListItem(i int) {
return
}
p := s.stack.parent()
- if !s.itemsBoundsCheck(p.v.Items, i) {
+ if !s.itemsBoundsCheck(p.v.GetItems(), i) {
return
}
if t := s.assertTypeList(p.t); t != nil {
s.stack.set(item{
i: i,
- t: t.ListType.Item,
- v: p.v.Items[i],
+ t: t.ListType.GetItem(),
+ v: p.v.GetItems()[i],
})
}
}
@@ -337,6 +369,7 @@ func (s *rawConverter) TupleIn() (size int) {
if s.assertTypeTuple(x.t) != nil {
return s.itemsIn()
}
+
return 0
}
@@ -345,14 +378,14 @@ func (s *rawConverter) TupleItem(i int) {
return
}
p := s.stack.parent()
- if !s.itemsBoundsCheck(p.v.Items, i) {
+ if !s.itemsBoundsCheck(p.v.GetItems(), i) {
return
}
if t := s.assertTypeTuple(p.t); t != nil {
s.stack.set(item{
i: i,
- t: t.TupleType.Elements[i],
- v: p.v.Items[i],
+ t: t.TupleType.GetElements()[i],
+ v: p.v.GetItems()[i],
})
}
}
@@ -375,6 +408,7 @@ func (s *rawConverter) StructIn() (size int) {
if s.assertTypeStruct(x.t) != nil {
return s.itemsIn()
}
+
return 0
}
@@ -383,19 +417,20 @@ func (s *rawConverter) StructField(i int) (name string) {
return
}
p := s.stack.parent()
- if !s.itemsBoundsCheck(p.v.Items, i) {
+ if !s.itemsBoundsCheck(p.v.GetItems(), i) {
return
}
if t := s.assertTypeStruct(p.t); t != nil {
- m := t.StructType.Members[i]
- name = m.Name
+ m := t.StructType.GetMembers()[i]
+ name = m.GetName()
s.stack.set(item{
- name: m.Name,
+ name: m.GetName(),
i: i,
- t: m.Type,
- v: p.v.Items[i],
+ t: m.GetType(),
+ v: p.v.GetItems()[i],
})
}
+
return
}
@@ -417,6 +452,7 @@ func (s *rawConverter) DictIn() (size int) {
if s.assertTypeDict(x.t) != nil {
return s.pairsIn()
}
+
return 0
}
@@ -425,14 +461,14 @@ func (s *rawConverter) DictKey(i int) {
return
}
p := s.stack.parent()
- if !s.pairsBoundsCheck(p.v.Pairs, i) {
+ if !s.pairsBoundsCheck(p.v.GetPairs(), i) {
return
}
if t := s.assertTypeDict(p.t); t != nil {
s.stack.set(item{
i: i,
- t: t.DictType.Key,
- v: p.v.Pairs[i].Key,
+ t: t.DictType.GetKey(),
+ v: p.v.GetPairs()[i].GetKey(),
})
}
}
@@ -442,14 +478,14 @@ func (s *rawConverter) DictPayload(i int) {
return
}
p := s.stack.parent()
- if !s.pairsBoundsCheck(p.v.Pairs, i) {
+ if !s.pairsBoundsCheck(p.v.GetPairs(), i) {
return
}
if t := s.assertTypeDict(p.t); t != nil {
s.stack.set(item{
i: i,
- t: t.DictType.Payload,
- v: p.v.Pairs[i].Payload,
+ t: t.DictType.GetPayload(),
+ v: p.v.GetPairs()[i].GetPayload(),
})
}
}
@@ -485,6 +521,7 @@ func (s *rawConverter) Variant() (name string, index uint32) {
t: typ,
v: v,
})
+
return name, index
}
@@ -498,13 +535,13 @@ func (s *rawConverter) Unwrap() {
return
}
v := x.v
- if isOptional(t.OptionalType.Item) {
+ if isOptional(t.OptionalType.GetItem()) {
v = s.unwrapValue()
}
s.stack.enter()
s.stack.set(item{
name: "*",
- t: t.OptionalType.Item,
+ t: t.OptionalType.GetItem(),
v: v,
})
}
@@ -517,22 +554,24 @@ func (s *rawConverter) Decimal(t types.Type) (v [16]byte) {
if !s.assertCurrentTypeDecimal(t) {
return
}
+
return s.uint128()
}
-func (s *rawConverter) UnwrapDecimal() (v types.Decimal) {
+func (s *rawConverter) UnwrapDecimal() decimal.Decimal {
if s.Err() != nil {
- return
+ return decimal.Decimal{}
}
s.unwrap()
d := s.assertTypeDecimal(s.stack.current().t)
if d == nil {
- return
+ return decimal.Decimal{}
}
- return types.Decimal{
+
+ return decimal.Decimal{
Bytes: s.uint128(),
- Precision: d.DecimalType.Precision,
- Scale: d.DecimalType.Scale,
+ Precision: d.DecimalType.GetPrecision(),
+ Scale: d.DecimalType.GetScale(),
}
}
@@ -540,37 +579,44 @@ func (s *rawConverter) IsDecimal() bool {
if s.Err() != nil {
return false
}
+
return s.isCurrentTypeDecimal()
}
func isEqualDecimal(d *Ydb.DecimalType, t types.Type) bool {
- w := t.(*value.DecimalType)
- return d.Precision == w.Precision && d.Scale == w.Scale
+ w := t.(*types.Decimal)
+
+ return d.GetPrecision() == w.Precision() && d.GetScale() == w.Scale()
}
func (s *rawConverter) isCurrentTypeDecimal() bool {
c := s.stack.current()
- _, ok := c.t.Type.(*Ydb.Type_DecimalType)
+ _, ok := c.t.GetType().(*Ydb.Type_DecimalType)
+
return ok
}
func (s *rawConverter) unwrapVariantType(typ *Ydb.Type_VariantType, index uint32) (name string, t *Ydb.Type) {
i := int(index)
- switch x := typ.VariantType.Type.(type) {
+ switch x := typ.VariantType.GetType().(type) {
case *Ydb.VariantType_TupleItems:
- if i >= len(x.TupleItems.Elements) {
+ if i >= len(x.TupleItems.GetElements()) {
_ = s.errorf(0, "unimplemented")
+
return
}
- return "", x.TupleItems.Elements[i]
+
+ return "", x.TupleItems.GetElements()[i]
case *Ydb.VariantType_StructItems:
- if i >= len(x.StructItems.Members) {
+ if i >= len(x.StructItems.GetMembers()) {
_ = s.errorf(0, "unimplemented")
+
return
}
- m := x.StructItems.Members[i]
- return m.Name, m.Type
+ m := x.StructItems.GetMembers()[i]
+
+ return m.GetName(), m.GetType()
default:
panic("unexpected variant items types")
@@ -583,7 +629,8 @@ func (s *rawConverter) variant() (v *Ydb.Value, index uint32) {
return
}
x := s.stack.current() // Is not nil if unwrapValue succeeded.
- index = x.v.VariantIndex
+ index = x.v.GetVariantIndex()
+
return
}
@@ -593,7 +640,8 @@ func (s *rawConverter) itemsIn() int {
return -1
}
s.stack.enter()
- return len(x.v.Items)
+
+ return len(x.v.GetItems())
}
func (s *rawConverter) itemsOut() {
@@ -610,7 +658,8 @@ func (s *rawConverter) pairsIn() int {
return -1
}
s.stack.enter()
- return len(x.v.Pairs)
+
+ return len(x.v.GetPairs())
}
func (s *rawConverter) pairsOut() {
@@ -624,16 +673,19 @@ func (s *rawConverter) pairsBoundsCheck(xs []*Ydb.ValuePair, i int) bool {
func (s *rawConverter) boundsCheck(n, i int) bool {
if i < 0 || n <= i {
s.boundsError(n, i)
+
return false
}
+
return true
}
-func (s *scanner) assertTypeOptional(typ *Ydb.Type) (t *Ydb.Type_OptionalType) {
- x := typ.Type
+func (s *valueScanner) assertTypeOptional(typ *Ydb.Type) (t *Ydb.Type_OptionalType) {
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_OptionalType); t == nil {
s.typeError(x, t)
}
+
return
}
@@ -655,13 +707,14 @@ func (s *rawConverter) assertCurrentTypeNullable() bool {
c.t,
p.t,
)
+
return false
}
func (s *rawConverter) assertCurrentTypeIs(t types.Type) bool {
c := s.stack.current()
- act := value.TypeFromYDB(c.t)
- if !value.TypesEqual(act, t) {
+ act := types.TypeFromYDB(c.t)
+ if !types.Equal(act, t) {
_ = s.errorf(
1,
"unexpected types at %q %s: %s; want %s",
@@ -670,8 +723,10 @@ func (s *rawConverter) assertCurrentTypeIs(t types.Type) bool {
act,
t,
)
+
return false
}
+
return true
}
@@ -682,56 +737,64 @@ func (s *rawConverter) assertCurrentTypeDecimal(t types.Type) bool {
}
if !isEqualDecimal(d.DecimalType, t) {
s.decimalTypeError(t)
+
return false
}
+
return true
}
func (s *rawConverter) assertTypeList(typ *Ydb.Type) (t *Ydb.Type_ListType) {
- x := typ.Type
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_ListType); t == nil {
s.typeError(x, t)
}
+
return
}
func (s *rawConverter) assertTypeTuple(typ *Ydb.Type) (t *Ydb.Type_TupleType) {
- x := typ.Type
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_TupleType); t == nil {
s.typeError(x, t)
}
+
return
}
func (s *rawConverter) assertTypeStruct(typ *Ydb.Type) (t *Ydb.Type_StructType) {
- x := typ.Type
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_StructType); t == nil {
s.typeError(x, t)
}
+
return
}
func (s *rawConverter) assertTypeDict(typ *Ydb.Type) (t *Ydb.Type_DictType) {
- x := typ.Type
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_DictType); t == nil {
s.typeError(x, t)
}
+
return
}
func (s *rawConverter) assertTypeDecimal(typ *Ydb.Type) (t *Ydb.Type_DecimalType) {
- x := typ.Type
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_DecimalType); t == nil {
s.typeError(x, t)
}
+
return
}
func (s *rawConverter) assertTypeVariant(typ *Ydb.Type) (t *Ydb.Type_VariantType) {
- x := typ.Type
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_VariantType); t == nil {
s.typeError(x, t)
}
+
return
}
@@ -756,8 +819,9 @@ func nameIface(v interface{}) string {
t := reflect.TypeOf(v)
s := t.String()
s = strings.TrimPrefix(s, "*Ydb.Value_")
- s = strings.TrimSuffix(s, "Value")
+ s = strings.TrimSuffix(s, "valueType")
s = strings.TrimPrefix(s, "*Ydb.Type_")
s = strings.TrimSuffix(s, "Type")
+
return s
}
diff --git a/internal/table/scanner/scanner.go b/internal/table/scanner/scanner.go
index 7334dc4d5..f541a1235 100644
--- a/internal/table/scanner/scanner.go
+++ b/internal/table/scanner/scanner.go
@@ -11,6 +11,9 @@ import (
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/decimal"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/scanner"
+ internalTypes "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
@@ -19,10 +22,9 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/indexed"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
-type scanner struct {
+type valueScanner struct {
set *Ydb.ResultSet
row *Ydb.Value
converter *rawConverter
@@ -39,56 +41,59 @@ type scanner struct {
}
// ColumnCount returns number of columns in the current result set.
-func (s *scanner) ColumnCount() int {
+func (s *valueScanner) ColumnCount() int {
if s.set == nil {
return 0
}
- return len(s.set.Columns)
+
+ return len(s.set.GetColumns())
}
// Columns allows to iterate over all columns of the current result set.
-func (s *scanner) Columns(it func(options.Column)) {
+func (s *valueScanner) Columns(it func(options.Column)) {
if s.set == nil {
return
}
- for _, m := range s.set.Columns {
+ for _, m := range s.set.GetColumns() {
it(options.Column{
- Name: m.Name,
- Type: value.TypeFromYDB(m.Type),
+ Name: m.GetName(),
+ Type: internalTypes.TypeFromYDB(m.GetType()),
})
}
}
// RowCount returns number of rows in the result set.
-func (s *scanner) RowCount() int {
+func (s *valueScanner) RowCount() int {
if s.set == nil {
return 0
}
- return len(s.set.Rows)
+
+ return len(s.set.GetRows())
}
// ItemCount returns number of items in the current row.
-func (s *scanner) ItemCount() int {
+func (s *valueScanner) ItemCount() int {
if s.row == nil {
return 0
}
- return len(s.row.Items)
+
+ return len(s.row.GetItems())
}
// HasNextRow reports whether result row may be advanced.
// It may be useful to call HasNextRow() instead of NextRow() to look ahead
// without advancing the result rows.
-func (s *scanner) HasNextRow() bool {
- return s.err == nil && s.set != nil && s.nextRow < len(s.set.Rows)
+func (s *valueScanner) HasNextRow() bool {
+ return s.err == nil && s.set != nil && s.nextRow < len(s.set.GetRows())
}
// NextRow selects next row in the current result set.
// It returns false if there are no more rows in the result set.
-func (s *scanner) NextRow() bool {
+func (s *valueScanner) NextRow() bool {
if !s.HasNextRow() {
return false
}
- s.row = s.set.Rows[s.nextRow]
+ s.row = s.set.GetRows()[s.nextRow]
s.nextRow++
s.nextItem = 0
s.stack.reset()
@@ -96,7 +101,7 @@ func (s *scanner) NextRow() bool {
return true
}
-func (s *scanner) preScanChecks(lenValues int) (err error) {
+func (s *valueScanner) preScanChecks(lenValues int) (err error) {
if s.columnIndexes != nil {
if len(s.columnIndexes) != lenValues {
return s.errorf(
@@ -113,10 +118,11 @@ func (s *scanner) preScanChecks(lenValues int) (err error) {
if s.nextItem != 0 {
panic("scan row failed: double scan per row")
}
+
return s.Err()
}
-func (s *scanner) ScanWithDefaults(values ...indexed.Required) (err error) {
+func (s *valueScanner) ScanWithDefaults(values ...indexed.Required) (err error) {
if err = s.preScanChecks(len(values)); err != nil {
return
}
@@ -140,10 +146,11 @@ func (s *scanner) ScanWithDefaults(values ...indexed.Required) (err error) {
}
}
s.nextItem += len(values)
+
return s.Err()
}
-func (s *scanner) Scan(values ...indexed.RequiredOrOptional) (err error) {
+func (s *valueScanner) Scan(values ...indexed.RequiredOrOptional) (err error) {
if err = s.preScanChecks(len(values)); err != nil {
return
}
@@ -167,10 +174,11 @@ func (s *scanner) Scan(values ...indexed.RequiredOrOptional) (err error) {
}
}
s.nextItem += len(values)
+
return s.Err()
}
-func (s *scanner) ScanNamed(namedValues ...named.Value) error {
+func (s *valueScanner) ScanNamed(namedValues ...named.Value) error {
if err := s.Err(); err != nil {
return err
}
@@ -192,32 +200,36 @@ func (s *scanner) ScanNamed(namedValues ...named.Value) error {
case named.TypeOptionalWithUseDefault:
s.scanOptional(namedValues[i].Value, true)
default:
- panic(fmt.Sprintf("unknown type of named.Value: %d", t))
+ panic(fmt.Sprintf("unknown type of named.valueType: %d", t))
}
}
s.nextItem += len(namedValues)
+
return s.Err()
}
// Truncated returns true if current result set has been truncated by server
-func (s *scanner) Truncated() bool {
+func (s *valueScanner) Truncated() bool {
if s.set == nil {
_ = s.errorf(0, "there are no sets in the scanner")
+
return false
}
- return s.set.Truncated
+
+ return s.set.GetTruncated()
}
// Truncated returns true if current result set has been truncated by server
-func (s *scanner) truncated() bool {
+func (s *valueScanner) truncated() bool {
if s.set == nil {
return false
}
- return s.set.Truncated
+
+ return s.set.GetTruncated()
}
// Err returns error caused Scanner to be broken.
-func (s *scanner) Err() error {
+func (s *valueScanner) Err() error {
s.errMtx.RLock()
defer s.errMtx.RUnlock()
if s.err != nil {
@@ -230,13 +242,15 @@ func (s *scanner) Err() error {
if s.markTruncatedAsRetryable {
err = xerrors.Retryable(err)
}
+
return xerrors.WithStackTrace(err)
}
+
return nil
}
// Must not be exported.
-func (s *scanner) reset(set *Ydb.ResultSet, columnNames ...string) {
+func (s *valueScanner) reset(set *Ydb.ResultSet, columnNames ...string) {
s.set = set
s.row = nil
s.nextRow = 0
@@ -245,18 +259,19 @@ func (s *scanner) reset(set *Ydb.ResultSet, columnNames ...string) {
s.setColumnIndexes(columnNames)
s.stack.reset()
s.converter = &rawConverter{
- scanner: s,
+ valueScanner: s,
}
}
-func (s *scanner) path() string {
+func (s *valueScanner) path() string {
buf := xstring.Buffer()
defer buf.Free()
_, _ = s.writePathTo(buf)
+
return buf.String()
}
-func (s *scanner) writePathTo(w io.Writer) (n int64, err error) {
+func (s *valueScanner) writePathTo(w io.Writer) (n int64, err error) {
x := s.stack.current()
st := x.name
m, err := io.WriteString(w, st)
@@ -264,65 +279,73 @@ func (s *scanner) writePathTo(w io.Writer) (n int64, err error) {
return n, xerrors.WithStackTrace(err)
}
n += int64(m)
+
return n, nil
}
-func (s *scanner) getType() types.Type {
+func (s *valueScanner) getType() internalTypes.Type {
x := s.stack.current()
if x.isEmpty() {
return nil
}
- return value.TypeFromYDB(x.t)
+
+ return internalTypes.TypeFromYDB(x.t)
}
-func (s *scanner) hasItems() bool {
+func (s *valueScanner) hasItems() bool {
return s.err == nil && s.set != nil && s.row != nil
}
-func (s *scanner) seekItemByID(id int) error {
- if !s.hasItems() || id >= len(s.set.Columns) {
+func (s *valueScanner) seekItemByID(id int) error {
+ if !s.hasItems() || id >= len(s.set.GetColumns()) {
return s.notFoundColumnByIndex(id)
}
- col := s.set.Columns[id]
- s.stack.scanItem.name = col.Name
- s.stack.scanItem.t = col.Type
- s.stack.scanItem.v = s.row.Items[id]
+ col := s.set.GetColumns()[id]
+ s.stack.scanItem.name = col.GetName()
+ s.stack.scanItem.t = col.GetType()
+ s.stack.scanItem.v = s.row.GetItems()[id]
+
return nil
}
-func (s *scanner) seekItemByName(name string) error {
+func (s *valueScanner) seekItemByName(name string) error {
if !s.hasItems() {
return s.notFoundColumnName(name)
}
- for i, c := range s.set.Columns {
- if name != c.Name {
+ for i, c := range s.set.GetColumns() {
+ if name != c.GetName() {
continue
}
- s.stack.scanItem.name = c.Name
- s.stack.scanItem.t = c.Type
- s.stack.scanItem.v = s.row.Items[i]
+ s.stack.scanItem.name = c.GetName()
+ s.stack.scanItem.t = c.GetType()
+ s.stack.scanItem.v = s.row.GetItems()[i]
+
return s.Err()
}
+
return s.notFoundColumnName(name)
}
-func (s *scanner) setColumnIndexes(columns []string) {
+func (s *valueScanner) setColumnIndexes(columns []string) {
if columns == nil {
s.columnIndexes = nil
+
return
}
s.columnIndexes = make([]int, len(columns))
for i, col := range columns {
found := false
- for j, c := range s.set.Columns {
- if c.Name == col {
+ for j, c := range s.set.GetColumns() {
+ if c.GetName() == col {
s.columnIndexes[i] = j
found = true
+
break
}
}
if !found {
_ = s.noColumnError(col)
+
return
}
}
@@ -347,7 +370,7 @@ func (s *scanner) setColumnIndexes(columns []string) {
// [16]byte
//
//nolint:gocyclo
-func (s *scanner) any() interface{} {
+func (s *valueScanner) any() interface{} {
x := s.stack.current()
if s.Err() != nil || x.isEmpty() {
return nil
@@ -362,97 +385,104 @@ func (s *scanner) any() interface{} {
x = s.stack.current()
}
- t := value.TypeFromYDB(x.t)
- p, primitive := t.(value.PrimitiveType)
+ t := internalTypes.TypeFromYDB(x.t)
+ p, primitive := t.(internalTypes.Primitive)
if !primitive {
return s.value()
}
switch p {
- case value.TypeBool:
+ case internalTypes.Bool:
return s.bool()
- case value.TypeInt8:
+ case internalTypes.Int8:
return s.int8()
- case value.TypeUint8:
+ case internalTypes.Uint8:
return s.uint8()
- case value.TypeInt16:
+ case internalTypes.Int16:
return s.int16()
- case value.TypeUint16:
+ case internalTypes.Uint16:
return s.uint16()
- case value.TypeInt32:
+ case internalTypes.Int32:
return s.int32()
- case value.TypeFloat:
+ case internalTypes.Float:
return s.float()
- case value.TypeDouble:
+ case internalTypes.Double:
return s.double()
- case value.TypeBytes:
+ case internalTypes.Bytes:
return s.bytes()
- case value.TypeUUID:
+ case internalTypes.UUID:
return s.uint128()
- case value.TypeUint32:
+ case internalTypes.Uint32:
return s.uint32()
- case value.TypeDate:
+ case internalTypes.Date:
return value.DateToTime(s.uint32())
- case value.TypeDatetime:
+ case internalTypes.Datetime:
return value.DatetimeToTime(s.uint32())
- case value.TypeUint64:
+ case internalTypes.Uint64:
return s.uint64()
- case value.TypeTimestamp:
+ case internalTypes.Timestamp:
return value.TimestampToTime(s.uint64())
- case value.TypeInt64:
+ case internalTypes.Int64:
return s.int64()
- case value.TypeInterval:
+ case internalTypes.Interval:
return value.IntervalToDuration(s.int64())
- case value.TypeTzDate:
+ case internalTypes.TzDate:
src, err := value.TzDateToTime(s.text())
if err != nil {
- _ = s.errorf(0, "scanner.any(): %w", err)
+ _ = s.errorf(0, "valueScanner.any(): %w", err)
}
+
return src
- case value.TypeTzDatetime:
+ case internalTypes.TzDatetime:
src, err := value.TzDatetimeToTime(s.text())
if err != nil {
- _ = s.errorf(0, "scanner.any(): %w", err)
+ _ = s.errorf(0, "valueScanner.any(): %w", err)
}
+
return src
- case value.TypeTzTimestamp:
+ case internalTypes.TzTimestamp:
src, err := value.TzTimestampToTime(s.text())
if err != nil {
- _ = s.errorf(0, "scanner.any(): %w", err)
+ _ = s.errorf(0, "valueScanner.any(): %w", err)
}
+
return src
- case value.TypeText, value.TypeDyNumber:
+ case internalTypes.Text, internalTypes.DyNumber:
return s.text()
case
- value.TypeYSON,
- value.TypeJSON,
- value.TypeJSONDocument:
+ internalTypes.YSON,
+ internalTypes.JSON,
+ internalTypes.JSONDocument:
return xstring.ToBytes(s.text())
default:
_ = s.errorf(0, "unknown primitive types")
+
return nil
}
}
-// Value returns current item under scan as ydb.Value types.
-func (s *scanner) value() types.Value {
+// valueType returns current item under scan as ydb.valueType types
+func (s *valueScanner) value() value.Value {
x := s.stack.current()
+
return value.FromYDB(x.t, x.v)
}
-func (s *scanner) isCurrentTypeOptional() bool {
+func (s *valueScanner) isCurrentTypeOptional() bool {
c := s.stack.current()
+
return isOptional(c.t)
}
-func (s *scanner) isNull() bool {
+func (s *valueScanner) isNull() bool {
_, yes := s.stack.currentValue().(*Ydb.Value_NullFlagValue)
+
return yes
}
-// unwrap current item under scan interpreting it as Optional types.
+// unwrap current item under scan interpreting it as Optional types
// ignores if type is not optional
-func (s *scanner) unwrap() {
+func (s *valueScanner) unwrap() {
if s.Err() != nil {
return
}
@@ -462,190 +492,224 @@ func (s *scanner) unwrap() {
return
}
- if isOptional(t.OptionalType.Item) {
+ if isOptional(t.OptionalType.GetItem()) {
s.stack.scanItem.v = s.unwrapValue()
}
- s.stack.scanItem.t = t.OptionalType.Item
+ s.stack.scanItem.t = t.OptionalType.GetItem()
}
-func (s *scanner) unwrapValue() (v *Ydb.Value) {
+func (s *valueScanner) unwrapValue() (v *Ydb.Value) {
x, _ := s.stack.currentValue().(*Ydb.Value_NestedValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.NestedValue
}
-func (s *scanner) unwrapDecimal() (v types.Decimal) {
+func (s *valueScanner) unwrapDecimal() decimal.Decimal {
if s.Err() != nil {
- return
+ return decimal.Decimal{}
}
s.unwrap()
d := s.assertTypeDecimal(s.stack.current().t)
if d == nil {
- return
+ return decimal.Decimal{}
}
- return types.Decimal{
+
+ return decimal.Decimal{
Bytes: s.uint128(),
- Precision: d.DecimalType.Precision,
- Scale: d.DecimalType.Scale,
+ Precision: d.DecimalType.GetPrecision(),
+ Scale: d.DecimalType.GetScale(),
}
}
-func (s *scanner) assertTypeDecimal(typ *Ydb.Type) (t *Ydb.Type_DecimalType) {
- x := typ.Type
+func (s *valueScanner) assertTypeDecimal(typ *Ydb.Type) (t *Ydb.Type_DecimalType) {
+ x := typ.GetType()
if t, _ = x.(*Ydb.Type_DecimalType); t == nil {
s.typeError(x, t)
}
+
return
}
-func (s *scanner) bool() (v bool) {
+func (s *valueScanner) bool() (v bool) {
x, _ := s.stack.currentValue().(*Ydb.Value_BoolValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.BoolValue
}
-func (s *scanner) int8() (v int8) {
+func (s *valueScanner) int8() (v int8) {
d := s.int32()
if d < math.MinInt8 || math.MaxInt8 < d {
_ = s.overflowError(d, v)
+
return
}
+
return int8(d)
}
-func (s *scanner) uint8() (v uint8) {
+func (s *valueScanner) uint8() (v uint8) {
d := s.uint32()
if d > math.MaxUint8 {
_ = s.overflowError(d, v)
+
return
}
+
return uint8(d)
}
-func (s *scanner) int16() (v int16) {
+func (s *valueScanner) int16() (v int16) {
d := s.int32()
if d < math.MinInt16 || math.MaxInt16 < d {
_ = s.overflowError(d, v)
+
return
}
+
return int16(d)
}
-func (s *scanner) uint16() (v uint16) {
+func (s *valueScanner) uint16() (v uint16) {
d := s.uint32()
if d > math.MaxUint16 {
_ = s.overflowError(d, v)
+
return
}
+
return uint16(d)
}
-func (s *scanner) int32() (v int32) {
+func (s *valueScanner) int32() (v int32) {
x, _ := s.stack.currentValue().(*Ydb.Value_Int32Value)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.Int32Value
}
-func (s *scanner) uint32() (v uint32) {
+func (s *valueScanner) uint32() (v uint32) {
x, _ := s.stack.currentValue().(*Ydb.Value_Uint32Value)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.Uint32Value
}
-func (s *scanner) int64() (v int64) {
+func (s *valueScanner) int64() (v int64) {
x, _ := s.stack.currentValue().(*Ydb.Value_Int64Value)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.Int64Value
}
-func (s *scanner) uint64() (v uint64) {
+func (s *valueScanner) uint64() (v uint64) {
x, _ := s.stack.currentValue().(*Ydb.Value_Uint64Value)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.Uint64Value
}
-func (s *scanner) float() (v float32) {
+func (s *valueScanner) float() (v float32) {
x, _ := s.stack.currentValue().(*Ydb.Value_FloatValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.FloatValue
}
-func (s *scanner) double() (v float64) {
+func (s *valueScanner) double() (v float64) {
x, _ := s.stack.currentValue().(*Ydb.Value_DoubleValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.DoubleValue
}
-func (s *scanner) bytes() (v []byte) {
+func (s *valueScanner) bytes() (v []byte) {
x, _ := s.stack.currentValue().(*Ydb.Value_BytesValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.BytesValue
}
-func (s *scanner) text() (v string) {
+func (s *valueScanner) text() (v string) {
x, _ := s.stack.currentValue().(*Ydb.Value_TextValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.TextValue
}
-func (s *scanner) low128() (v uint64) {
+func (s *valueScanner) low128() (v uint64) {
x, _ := s.stack.currentValue().(*Ydb.Value_Low_128)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
+
return
}
+
return x.Low_128
}
-func (s *scanner) uint128() (v [16]byte) {
+func (s *valueScanner) uint128() (v [16]byte) {
c := s.stack.current()
if c.isEmpty() {
_ = s.errorf(0, "not implemented convert to [16]byte")
+
return
}
lo := s.low128()
- hi := c.v.High_128
+ hi := c.v.GetHigh_128()
+
return value.BigEndianUint128(hi, lo)
}
-func (s *scanner) null() {
+func (s *valueScanner) null() {
x, _ := s.stack.currentValue().(*Ydb.Value_NullFlagValue)
if x == nil {
s.valueTypeError(s.stack.currentValue(), x)
}
}
-func (s *scanner) setTime(dst *time.Time) {
+func (s *valueScanner) setTime(dst *time.Time) {
switch t := s.stack.current().t.GetTypeId(); t {
case Ydb.Type_DATE:
*dst = value.DateToTime(s.uint32())
@@ -656,27 +720,27 @@ func (s *scanner) setTime(dst *time.Time) {
case Ydb.Type_TZ_DATE:
src, err := value.TzDateToTime(s.text())
if err != nil {
- _ = s.errorf(0, "scanner.setTime(): %w", err)
+ _ = s.errorf(0, "valueScanner.setTime(): %w", err)
}
*dst = src
case Ydb.Type_TZ_DATETIME:
src, err := value.TzDatetimeToTime(s.text())
if err != nil {
- _ = s.errorf(0, "scanner.setTime(): %w", err)
+ _ = s.errorf(0, "valueScanner.setTime(): %w", err)
}
*dst = src
case Ydb.Type_TZ_TIMESTAMP:
src, err := value.TzTimestampToTime(s.text())
if err != nil {
- _ = s.errorf(0, "scanner.setTime(): %w", err)
+ _ = s.errorf(0, "valueScanner.setTime(): %w", err)
}
*dst = src
default:
- _ = s.errorf(0, "scanner.setTime(): incorrect source types %s", t)
+ _ = s.errorf(0, "valueScanner.setTime(): incorrect source types %s", t)
}
}
-func (s *scanner) setString(dst *string) {
+func (s *valueScanner) setString(dst *string) {
switch t := s.stack.current().t.GetTypeId(); t {
case Ydb.Type_UUID:
src := s.uint128()
@@ -690,7 +754,7 @@ func (s *scanner) setString(dst *string) {
}
}
-func (s *scanner) setByte(dst *[]byte) {
+func (s *valueScanner) setByte(dst *[]byte) {
switch t := s.stack.current().t.GetTypeId(); t {
case Ydb.Type_UUID:
src := s.uint128()
@@ -704,7 +768,7 @@ func (s *scanner) setByte(dst *[]byte) {
}
}
-func (s *scanner) trySetByteArray(v interface{}, optional, def bool) bool {
+func (s *valueScanner) trySetByteArray(v interface{}, optional, def bool) bool {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
@@ -715,6 +779,7 @@ func (s *scanner) trySetByteArray(v interface{}, optional, def bool) bool {
}
if s.isNull() {
rv.Set(reflect.Zero(rv.Type()))
+
return true
}
if rv.IsZero() {
@@ -731,6 +796,7 @@ func (s *scanner) trySetByteArray(v interface{}, optional, def bool) bool {
}
if def {
rv.Set(reflect.Zero(rv.Type()))
+
return true
}
var dst []byte
@@ -739,11 +805,12 @@ func (s *scanner) trySetByteArray(v interface{}, optional, def bool) bool {
return false
}
reflect.Copy(rv, reflect.ValueOf(dst))
+
return true
}
//nolint:gocyclo
-func (s *scanner) scanRequired(v interface{}) {
+func (s *valueScanner) scanRequired(v interface{}) {
switch v := v.(type) {
case *bool:
*v = s.bool()
@@ -783,11 +850,11 @@ func (s *scanner) scanRequired(v interface{}) {
*v = s.uint128()
case *interface{}:
*v = s.any()
- case *types.Value:
+ case *value.Value:
*v = s.value()
- case *types.Decimal:
+ case *decimal.Decimal:
*v = s.unwrapDecimal()
- case types.Scanner:
+ case scanner.Scanner:
err := v.UnmarshalYDB(s.converter)
if err != nil {
_ = s.errorf(0, "ydb.Scanner error: %w", err)
@@ -800,9 +867,9 @@ func (s *scanner) scanRequired(v interface{}) {
case json.Unmarshaler:
var err error
switch s.getType() {
- case types.TypeJSON:
+ case internalTypes.JSON:
err = v.UnmarshalJSON(s.converter.JSON())
- case types.TypeJSONDocument:
+ case internalTypes.JSONDocument:
err = v.UnmarshalJSON(s.converter.JSONDocument())
default:
_ = s.errorf(0, "ydb required type %T not unsupported for applying to json.Unmarshaler", s.getType())
@@ -819,7 +886,7 @@ func (s *scanner) scanRequired(v interface{}) {
}
//nolint:gocyclo
-func (s *scanner) scanOptional(v interface{}, defaultValueForOptional bool) {
+func (s *valueScanner) scanOptional(v interface{}, defaultValueForOptional bool) {
if defaultValueForOptional {
if s.isNull() {
s.setDefaultValue(v)
@@ -827,6 +894,7 @@ func (s *scanner) scanOptional(v interface{}, defaultValueForOptional bool) {
s.unwrap()
s.scanRequired(v)
}
+
return
}
switch v := v.(type) {
@@ -969,16 +1037,16 @@ func (s *scanner) scanOptional(v interface{}, defaultValueForOptional bool) {
src := s.any()
*v = &src
}
- case *types.Value:
+ case *value.Value:
*v = s.value()
- case **types.Decimal:
+ case **decimal.Decimal:
if s.isNull() {
*v = nil
} else {
src := s.unwrapDecimal()
*v = &src
}
- case types.Scanner:
+ case scanner.Scanner:
err := v.UnmarshalYDB(s.converter)
if err != nil {
_ = s.errorf(0, "ydb.Scanner error: %w", err)
@@ -992,13 +1060,13 @@ func (s *scanner) scanOptional(v interface{}, defaultValueForOptional bool) {
s.unwrap()
var err error
switch s.getType() {
- case types.TypeJSON:
+ case internalTypes.JSON:
if s.isNull() {
err = v.UnmarshalJSON(nil)
} else {
err = v.UnmarshalJSON(s.converter.JSON())
}
- case types.TypeJSONDocument:
+ case internalTypes.JSONDocument:
if s.isNull() {
err = v.UnmarshalJSON(nil)
} else {
@@ -1024,7 +1092,7 @@ func (s *scanner) scanOptional(v interface{}, defaultValueForOptional bool) {
}
}
-func (s *scanner) setDefaultValue(dst interface{}) {
+func (s *valueScanner) setDefaultValue(dst interface{}) {
switch v := dst.(type) {
case *bool:
*v = false
@@ -1060,16 +1128,16 @@ func (s *scanner) setDefaultValue(dst interface{}) {
*v = [16]byte{}
case *interface{}:
*v = nil
- case *types.Value:
+ case *value.Value:
*v = s.value()
- case *types.Decimal:
- *v = types.Decimal{}
+ case *decimal.Decimal:
+ *v = decimal.Decimal{}
case sql.Scanner:
err := v.Scan(nil)
if err != nil {
_ = s.errorf(0, "sql.Scanner error: %w", err)
}
- case types.Scanner:
+ case scanner.Scanner:
err := v.UnmarshalYDB(s.converter)
if err != nil {
_ = s.errorf(0, "ydb.Scanner error: %w", err)
@@ -1093,17 +1161,18 @@ func (r *baseResult) SetErr(err error) {
})
}
-func (s *scanner) errorf(depth int, f string, args ...interface{}) error {
+func (s *valueScanner) errorf(depth int, f string, args ...interface{}) error {
s.errMtx.Lock()
defer s.errMtx.Unlock()
if s.err != nil {
return s.err
}
s.err = xerrors.WithStackTrace(fmt.Errorf(f, args...), xerrors.WithSkipDepth(depth+1))
+
return s.err
}
-func (s *scanner) typeError(act, exp interface{}) {
+func (s *valueScanner) typeError(act, exp interface{}) {
_ = s.errorf(
2,
"unexpected types during scan at %q %s: %s; want %s",
@@ -1114,7 +1183,7 @@ func (s *scanner) typeError(act, exp interface{}) {
)
}
-func (s *scanner) valueTypeError(act, exp interface{}) {
+func (s *valueScanner) valueTypeError(act, exp interface{}) {
// unexpected value during scan at \"migration_status\" Int64: NullFlag; want Int64
_ = s.errorf(
2,
@@ -1126,7 +1195,7 @@ func (s *scanner) valueTypeError(act, exp interface{}) {
)
}
-func (s *scanner) notFoundColumnByIndex(idx int) error {
+func (s *valueScanner) notFoundColumnByIndex(idx int) error {
return s.errorf(
2,
"not found %d column",
@@ -1134,7 +1203,7 @@ func (s *scanner) notFoundColumnByIndex(idx int) error {
)
}
-func (s *scanner) notFoundColumnName(name string) error {
+func (s *valueScanner) notFoundColumnName(name string) error {
return s.errorf(
2,
"not found column '%s'",
@@ -1142,7 +1211,7 @@ func (s *scanner) notFoundColumnName(name string) error {
)
}
-func (s *scanner) noColumnError(name string) error {
+func (s *valueScanner) noColumnError(name string) error {
return s.errorf(
2,
"no column %q",
@@ -1150,7 +1219,7 @@ func (s *scanner) noColumnError(name string) error {
)
}
-func (s *scanner) overflowError(i, n interface{}) error {
+func (s *valueScanner) overflowError(i, n interface{}) error {
return s.errorf(
2,
"overflow error: %d overflows capacity of %t",
@@ -1163,7 +1232,7 @@ var emptyItem item
type item struct {
name string
- i int // Index in listing types.
+ i int // Index in listing types
t *Ydb.Type
v *Ydb.Value
}
@@ -1182,6 +1251,7 @@ func (s *scanStack) size() int {
if !s.scanItem.isEmpty() {
s.set(s.scanItem)
}
+
return s.p + 1
}
@@ -1222,6 +1292,7 @@ func (s *scanStack) parent() item {
if s.p == 0 {
return emptyItem
}
+
return s.v[s.p-1]
}
@@ -1232,20 +1303,23 @@ func (s *scanStack) current() item {
if s.v == nil {
return emptyItem
}
+
return s.v[s.p]
}
func (s *scanStack) currentValue() interface{} {
if v := s.current().v; v != nil {
- return v.Value
+ return v.GetValue()
}
+
return nil
}
func (s *scanStack) currentType() interface{} {
if t := s.current().t; t != nil {
- return t.Type
+ return t.GetType()
}
+
return nil
}
@@ -1253,6 +1327,7 @@ func isOptional(typ *Ydb.Type) bool {
if typ == nil {
return false
}
- _, yes := typ.Type.(*Ydb.Type_OptionalType)
+ _, yes := typ.GetType().(*Ydb.Type_OptionalType)
+
return yes
}
diff --git a/internal/table/scanner/scanner_data_test.go b/internal/table/scanner/scanner_data_test.go
index c3d7c73a2..f47fffbac 100644
--- a/internal/table/scanner/scanner_data_test.go
+++ b/internal/table/scanner/scanner_data_test.go
@@ -29,6 +29,7 @@ func (s *intIncScanner) Scan(src interface{}) error {
return fmt.Errorf("wrong type: %T, exp: int64", src)
}
*s = intIncScanner(v + 10)
+
return nil
}
@@ -40,6 +41,7 @@ func (s *dateScanner) Scan(src interface{}) error {
return fmt.Errorf("wrong type: %T, exp: time.Time", src)
}
*s = dateScanner(v)
+
return nil
}
@@ -206,7 +208,7 @@ var scannerData = []struct {
setColumnIndexes: []int{0, 2, 1},
},
{
- name: "Scan int64, float, json as ydb.Value",
+ name: "Scan int64, float, json as ydb.valueType",
count: 100,
columns: []*column{{
name: "valueint64",
@@ -468,8 +470,8 @@ var scannerData = []struct {
},
}
-func initScanner() *scanner {
- res := scanner{
+func initScanner() *valueScanner {
+ res := valueScanner{
set: &Ydb.ResultSet{
Columns: nil,
Rows: nil,
@@ -485,10 +487,11 @@ func initScanner() *scanner {
columnIndexes: nil,
err: nil,
}
+
return &res
}
-func PrepareScannerPerformanceTest(count int) *scanner {
+func PrepareScannerPerformanceTest(count int) *valueScanner {
res := initScanner()
res.set.Columns = []*Ydb.Column{{
Name: "series_id",
@@ -526,7 +529,7 @@ func PrepareScannerPerformanceTest(count int) *scanner {
}}
res.set.Rows = []*Ydb.Value{}
for i := 0; i < count; i++ {
- res.set.Rows = append(res.set.Rows, &Ydb.Value{
+ res.set.Rows = append(res.set.GetRows(), &Ydb.Value{
Items: []*Ydb.Value{{
Value: &Ydb.Value_Uint64Value{
Uint64Value: uint64(i),
@@ -543,5 +546,6 @@ func PrepareScannerPerformanceTest(count int) *scanner {
})
}
res.converter = &rawConverter{res}
+
return res
}
diff --git a/internal/table/scanner/scanner_test.go b/internal/table/scanner/scanner_test.go
index c0dcb4c5f..44f09ff45 100644
--- a/internal/table/scanner/scanner_test.go
+++ b/internal/table/scanner/scanner_test.go
@@ -31,8 +31,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_INT8:
v := int8(rv)
@@ -43,8 +45,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_UINT8:
if c.nilValue {
@@ -53,9 +57,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv uint8
+
return ydbval, &dv
}
var dv *uint8
+
return ydbval, &dv
}
v := uint8(rv)
@@ -66,8 +72,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_INT16:
v := int16(rv)
@@ -78,8 +86,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_UINT16:
v := uint16(rv)
@@ -90,8 +100,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_INT32:
if c.nilValue {
@@ -100,9 +112,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv int32
+
return ydbval, &dv
}
var dv *int32
+
return ydbval, &dv
}
v := int32(rv)
@@ -113,8 +127,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_UINT32:
v := uint32(rv)
@@ -125,8 +141,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_INT64:
v := rv
@@ -137,16 +155,20 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.ydbvalue {
vp := types.Int64Value(v)
+
return ydbval, &vp
}
if c.scanner {
s := intIncScanner(v + 10)
+
return ydbval, &s
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_UINT64:
v := uint64(rv)
@@ -157,8 +179,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_FLOAT:
v := float32(rv)
@@ -169,12 +193,15 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.ydbvalue {
vp := types.FloatValue(v)
+
return ydbval, &vp
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_DOUBLE:
v := float64(rv)
@@ -185,8 +212,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_DATE:
v := uint32(rv)
@@ -198,12 +227,15 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := value.DateToTime(v)
if c.scanner {
s := dateScanner(src)
+
return ydbval, &s
}
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_DATETIME:
v := uint32(rv)
@@ -215,8 +247,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := value.DatetimeToTime(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_TIMESTAMP:
v := uint64(rv)
@@ -228,8 +262,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := value.TimestampToTime(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_INTERVAL:
if c.nilValue {
@@ -238,9 +274,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv time.Duration
+
return ydbval, &dv
}
var dv *time.Duration
+
return ydbval, &dv
}
rv %= time.Now().Unix()
@@ -253,8 +291,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := value.IntervalToDuration(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_TZ_DATE:
v := time.Now().Format(value.LayoutDate) + ",Europe/Berlin"
@@ -266,8 +306,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src, _ := value.TzDateToTime(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_TZ_DATETIME:
if c.nilValue {
@@ -276,9 +318,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv time.Time
+
return ydbval, &dv
}
var dv *time.Time
+
return ydbval, &dv
}
rv %= time.Now().Unix()
@@ -291,8 +335,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src, _ := value.TzDatetimeToTime(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_TZ_TIMESTAMP:
rv %= time.Now().Unix()
@@ -305,8 +351,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src, _ := value.TzTimestampToTime(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_STRING:
if c.nilValue {
@@ -315,9 +363,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv []byte
+
return ydbval, &dv
}
var dv *[]byte
+
return ydbval, &dv
}
v := make([]byte, 16)
@@ -331,8 +381,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := v
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_UTF8:
v := strconv.FormatUint(uint64(rv), 10)
@@ -343,8 +395,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_YSON:
if c.nilValue {
@@ -353,9 +407,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv []byte
+
return ydbval, &dv
}
var dv *[]byte
+
return ydbval, &dv
}
v := strconv.FormatUint(uint64(rv), 10)
@@ -367,8 +423,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := []byte(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_JSON:
v := strconv.FormatUint(uint64(rv), 10)
@@ -379,13 +437,16 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.ydbvalue {
vp := types.JSONValue(v)
+
return ydbval, &vp
}
src := []byte(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_UUID:
if c.nilValue {
@@ -394,9 +455,11 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.testDefault {
var dv [16]byte
+
return ydbval, &dv
}
var dv *[16]byte
+
return ydbval, &dv
}
v := [16]byte{}
@@ -410,8 +473,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
case Ydb.Type_JSON_DOCUMENT:
v := strconv.FormatUint(uint64(rv), 10)
@@ -423,8 +488,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
src := []byte(v)
if c.optional && !c.testDefault {
vp := &src
+
return ydbval, &vp
}
+
return ydbval, &src
case Ydb.Type_DYNUMBER:
v := strconv.FormatUint(uint64(rv), 10)
@@ -435,8 +502,10 @@ func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{})
}
if c.optional && !c.testDefault {
vp := &v
+
return ydbval, &vp
}
+
return ydbval, &v
default:
panic("ydb: unexpected types")
@@ -461,7 +530,7 @@ func getResultSet(count int, col []*column) (result *Ydb.ResultSet, testValues [
}
}
result.Columns = append(
- result.Columns,
+ result.GetColumns(),
&Ydb.Column{
Name: c.name,
Type: t,
@@ -474,16 +543,17 @@ func getResultSet(count int, col []*column) (result *Ydb.ResultSet, testValues [
for i := 0; i < count; i++ {
var items []*Ydb.Value
var vals []indexed.RequiredOrOptional
- for j := range result.Columns {
+ for j := range result.GetColumns() {
v, val := valueFromPrimitiveTypeID(col[j], r)
vals = append(vals, val)
items = append(items, v)
}
- result.Rows = append(result.Rows, &Ydb.Value{
+ result.Rows = append(result.GetRows(), &Ydb.Value{
Items: items,
})
testValues[i] = vals
}
+
return result, testValues
}
@@ -499,6 +569,7 @@ func TestScanSqlTypes(t *testing.T) {
for _, v := range test.values {
values = append(values, v)
}
+
return values
}()...); err != nil {
t.Fatalf("test: %s; error: %s", test.name, err)
@@ -527,6 +598,7 @@ func TestScanNamed(t *testing.T) {
if columns == nil {
return defaultValue
}
+
return columns[i]
}
for _, test := range scannerData {
@@ -602,6 +674,7 @@ type jsonUnmarshaller struct {
func (json *jsonUnmarshaller) UnmarshalJSON(bytes []byte) error {
json.bytes = bytes
+
return nil
}
diff --git a/internal/table/scanner/stats.go b/internal/table/scanner/stats.go
index cfe3295aa..d9772e34c 100644
--- a/internal/table/scanner/stats.go
+++ b/internal/table/scanner/stats.go
@@ -20,13 +20,14 @@ func (s *queryStats) ProcessCPUTime() time.Duration {
}
func (s *queryStats) Compilation() (c *stats.CompilationStats) {
- if s.stats == nil || s.stats.Compilation == nil {
+ if s.stats == nil || s.stats.GetCompilation() == nil {
return nil
}
+
return &stats.CompilationStats{
- FromCache: s.stats.Compilation.FromCache,
- Duration: time.Microsecond * time.Duration(s.stats.Compilation.DurationUs),
- CPUTime: time.Microsecond * time.Duration(s.stats.Compilation.CpuTimeUs),
+ FromCache: s.stats.GetCompilation().GetFromCache(),
+ Duration: time.Microsecond * time.Duration(s.stats.GetCompilation().GetDurationUs()),
+ CPUTime: time.Microsecond * time.Duration(s.stats.GetCompilation().GetCpuTimeUs()),
}
}
@@ -39,31 +40,32 @@ func (s *queryStats) QueryAST() string {
}
func (s *queryStats) TotalCPUTime() time.Duration {
- return time.Microsecond * time.Duration(s.stats.TotalCpuTimeUs)
+ return time.Microsecond * time.Duration(s.stats.GetTotalCpuTimeUs())
}
func (s *queryStats) TotalDuration() time.Duration {
- return time.Microsecond * time.Duration(s.stats.TotalDurationUs)
+ return time.Microsecond * time.Duration(s.stats.GetTotalDurationUs())
}
// NextPhase returns next execution phase within query.
// If ok flag is false, then there are no more phases and p is invalid.
func (s *queryStats) NextPhase() (p stats.QueryPhase, ok bool) {
- if s.pos >= len(s.stats.QueryPhases) {
+ if s.pos >= len(s.stats.GetQueryPhases()) {
return
}
- x := s.stats.QueryPhases[s.pos]
+ x := s.stats.GetQueryPhases()[s.pos]
if x == nil {
return
}
s.pos++
+
return &queryPhase{
- tables: x.TableAccess,
+ tables: x.GetTableAccess(),
pos: 0,
- duration: time.Microsecond * time.Duration(x.DurationUs),
- cpuTime: time.Microsecond * time.Duration(x.CpuTimeUs),
- affectedShards: x.AffectedShards,
- literalPhase: x.LiteralPhase,
+ duration: time.Microsecond * time.Duration(x.GetDurationUs()),
+ cpuTime: time.Microsecond * time.Duration(x.GetCpuTimeUs()),
+ affectedShards: x.GetAffectedShards(),
+ literalPhase: x.GetLiteralPhase(),
}, true
}
@@ -87,11 +89,12 @@ func (q *queryPhase) NextTableAccess() (t *stats.TableAccess, ok bool) {
}
x := q.tables[q.pos]
q.pos++
+
return &stats.TableAccess{
- Name: x.Name,
- Reads: initOperationStats(x.Reads),
- Updates: initOperationStats(x.Updates),
- Deletes: initOperationStats(x.Deletes),
+ Name: x.GetName(),
+ Reads: initOperationStats(x.GetReads()),
+ Updates: initOperationStats(x.GetUpdates()),
+ Deletes: initOperationStats(x.GetDeletes()),
}, true
}
@@ -115,8 +118,9 @@ func initOperationStats(x *Ydb_TableStats.OperationStats) stats.OperationStats {
if x == nil {
return stats.OperationStats{}
}
+
return stats.OperationStats{
- Rows: x.Rows,
- Bytes: x.Bytes,
+ Rows: x.GetRows(),
+ Bytes: x.GetBytes(),
}
}
diff --git a/internal/table/session.go b/internal/table/session.go
index 045ebc00d..3c9fe585c 100644
--- a/internal/table/session.go
+++ b/internal/table/session.go
@@ -6,6 +6,7 @@ import (
"net/url"
"strconv"
"sync"
+ "sync/atomic"
"time"
"github.com/ydb-platform/ydb-go-genproto/Ydb_Table_V1"
@@ -21,18 +22,18 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/feature"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/meta"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/scanner"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
@@ -44,17 +45,15 @@ import (
// Note that after session is no longer needed it should be destroyed by
// Close() call.
type session struct {
+ onClose []func(s *session)
id string
tableService Ydb_Table_V1.TableServiceClient
+ status table.SessionStatus
config *config.Config
-
- status table.SessionStatus
- statusMtx sync.RWMutex
- nodeID xatomic.Uint32
- lastUsage xatomic.Int64
-
- onClose []func(s *session)
- closeOnce sync.Once
+ lastUsage atomic.Int64
+ statusMtx sync.RWMutex
+ closeOnce sync.Once
+ nodeID atomic.Uint32
}
func (s *session) LastUsage() time.Time {
@@ -70,6 +69,7 @@ func nodeID(sessionID string) (uint32, error) {
if err != nil {
return 0, err
}
+
return uint32(id), err
}
@@ -85,6 +85,7 @@ func (s *session) NodeID() uint32 {
return 0
}
s.nodeID.Store(id)
+
return id
}
@@ -94,6 +95,7 @@ func (s *session) Status() table.SessionStatus {
}
s.statusMtx.RLock()
defer s.statusMtx.RUnlock()
+
return s.status
}
@@ -114,7 +116,9 @@ func (s *session) isClosing() bool {
func newSession(ctx context.Context, cc grpc.ClientConnInterface, config *config.Config) (
s *session, err error,
) {
- onDone := trace.TableOnSessionNew(config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnSessionNew(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.newSession"),
+ )
defer func() {
onDone(s, err)
}()
@@ -166,6 +170,7 @@ func (s *session) ID() string {
if s == nil {
return ""
}
+
return s.id
}
@@ -176,7 +181,7 @@ func (s *session) Close(ctx context.Context) (err error) {
s.closeOnce.Do(func() {
onDone := trace.TableOnSessionDelete(s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Close"),
s,
)
defer func() {
@@ -228,7 +233,7 @@ func (s *session) KeepAlive(ctx context.Context) (err error) {
result Ydb_Table.KeepAliveResult
onDone = trace.TableOnSessionKeepAlive(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).KeepAlive"),
s,
)
)
@@ -256,12 +261,13 @@ func (s *session) KeepAlive(ctx context.Context) (err error) {
return xerrors.WithStackTrace(err)
}
- switch result.SessionStatus {
+ switch result.GetSessionStatus() {
case Ydb_Table.KeepAliveResult_SESSION_STATUS_READY:
s.SetStatus(table.SessionReady)
case Ydb_Table.KeepAliveResult_SESSION_STATUS_BUSY:
s.SetStatus(table.SessionBusy)
}
+
return nil
}
@@ -294,6 +300,7 @@ func (s *session) CreateTable(
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -335,10 +342,10 @@ func (s *session) DescribeTable(
[]options.Column,
len(result.GetColumns()),
)
- for i, c := range result.Columns {
+ for i, c := range result.GetColumns() {
cs[i] = options.Column{
Name: c.GetName(),
- Type: value.TypeFromYDB(c.GetType()),
+ Type: types.TypeFromYDB(c.GetType()),
Family: c.GetFamily(),
}
}
@@ -347,7 +354,7 @@ func (s *session) DescribeTable(
[]options.KeyRange,
len(result.GetShardKeyBounds())+1,
)
- var last types.Value
+ var last value.Value
for i, b := range result.GetShardKeyBounds() {
if last != nil {
rs[i].From = last
@@ -370,18 +377,18 @@ func (s *session) DescribeTable(
[]options.PartitionStats,
len(result.GetTableStats().GetPartitionStats()),
)
- for i, v := range result.TableStats.PartitionStats {
+ for i, v := range result.GetTableStats().GetPartitionStats() {
partStats[i].RowsEstimate = v.GetRowsEstimate()
partStats[i].StoreSize = v.GetStoreSize()
}
var creationTime, modificationTime time.Time
- if resStats.CreationTime.GetSeconds() != 0 {
+ if resStats.GetCreationTime().GetSeconds() != 0 {
creationTime = time.Unix(
resStats.GetCreationTime().GetSeconds(),
int64(resStats.GetCreationTime().GetNanos()),
)
}
- if resStats.ModificationTime.GetSeconds() != 0 {
+ if resStats.GetModificationTime().GetSeconds() != 0 {
modificationTime = time.Unix(
resStats.GetModificationTime().GetSeconds(),
int64(resStats.GetModificationTime().GetNanos()),
@@ -408,10 +415,10 @@ func (s *session) DescribeTable(
attrs[k] = v
}
- indexes := make([]options.IndexDescription, len(result.Indexes))
+ indexes := make([]options.IndexDescription, len(result.GetIndexes()))
for i, idx := range result.GetIndexes() {
var typ options.IndexType
- switch idx.Type.(type) {
+ switch idx.GetType().(type) {
case *Ydb_Table.TableIndexDescription_GlobalAsyncIndex:
typ = options.IndexTypeGlobalAsync
case *Ydb_Table.TableIndexDescription_GlobalIndex:
@@ -426,7 +433,7 @@ func (s *session) DescribeTable(
}
}
- changeFeeds := make([]options.ChangefeedDescription, len(result.Changefeeds))
+ changeFeeds := make([]options.ChangefeedDescription, len(result.GetChangefeeds()))
for i, proto := range result.GetChangefeeds() {
changeFeeds[i] = options.NewChangefeedDescription(proto)
}
@@ -472,6 +479,7 @@ func (s *session) DropTable(
}
}
_, err = s.tableService.DropTable(ctx, &request)
+
return xerrors.WithStackTrace(err)
}
@@ -479,7 +487,7 @@ func (s *session) checkError(err error) {
if err == nil {
return
}
- if m := retry.Check(err); m.MustDeleteSession() {
+ if m := retry.Check(err); m.IsRetryObjectValid() {
s.SetStatus(table.SessionClosing)
}
}
@@ -510,6 +518,7 @@ func (s *session) AlterTable(
}
}
_, err = s.tableService.AlterTable(ctx, &request)
+
return xerrors.WithStackTrace(err)
}
@@ -539,6 +548,7 @@ func (s *session) CopyTable(
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -568,13 +578,14 @@ func copyTables(
opt((*options.CopyTablesDesc)(&request))
}
}
- if len(request.Tables) == 0 {
+ if len(request.GetTables()) == 0 {
return xerrors.WithStackTrace(fmt.Errorf("no CopyTablesItem: %w", errParamsRequired))
}
_, err = service.CopyTables(ctx, &request)
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -587,6 +598,7 @@ func (s *session) CopyTables(
if err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
@@ -603,7 +615,7 @@ func (s *session) Explain(
response *Ydb_Table.ExplainDataQueryResponse
onDone = trace.TableOnSessionQueryExplain(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Explain"),
s, query,
)
)
@@ -640,7 +652,7 @@ func (s *session) Explain(
Explanation: table.Explanation{
Plan: result.GetQueryPlan(),
},
- AST: result.QueryAst,
+ AST: result.GetQueryAst(),
}, nil
}
@@ -652,7 +664,7 @@ func (s *session) Prepare(ctx context.Context, queryText string) (_ table.Statem
result Ydb_Table.PrepareQueryResult
onDone = trace.TableOnSessionQueryPrepare(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Prepare"),
s, queryText,
)
)
@@ -688,7 +700,7 @@ func (s *session) Prepare(ctx context.Context, queryText string) (_ table.Statem
stmt = &statement{
session: s,
query: queryPrepared(result.GetQueryId(), queryText),
- params: result.ParametersTypes,
+ params: result.GetParametersTypes(),
}
return stmt, nil
@@ -699,7 +711,7 @@ func (s *session) Execute(
ctx context.Context,
txControl *table.TransactionControl,
query string,
- params *table.QueryParameters,
+ parameters *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (
txr table.Transaction, r result.Result, err error,
@@ -717,10 +729,10 @@ func (s *session) Execute(
request.SessionId = s.id
request.TxControl = txControl.Desc()
- request.Parameters = params.Params().ToYDB(a)
+ request.Parameters = parameters.ToYDB(a)
request.Query = q.toYDB(a)
request.QueryCachePolicy = a.TableQueryCachePolicy()
- request.QueryCachePolicy.KeepInCache = len(params.Params()) > 0
+ request.QueryCachePolicy.KeepInCache = len(request.Parameters) > 0
request.OperationParams = operation.Params(ctx,
s.config.OperationTimeout(),
s.config.OperationCancelAfter(),
@@ -735,8 +747,8 @@ func (s *session) Execute(
onDone := trace.TableOnSessionQueryExecute(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
- s, q, params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Execute"),
+ s, q, parameters,
request.QueryCachePolicy.GetKeepInCache(),
)
defer func() {
@@ -764,12 +776,13 @@ func (s *session) executeQueryResult(
id: res.GetTxMeta().GetId(),
s: s,
}
- if txControl.CommitTx {
+ if txControl.GetCommitTx() {
tx.state.Store(txStateCommitted)
} else {
tx.state.Store(txStateInitialized)
tx.control = table.TxControl(table.WithTxID(tx.id))
}
+
return tx, scanner.NewUnary(
res.GetResultSets(),
res.GetQueryStats(),
@@ -825,6 +838,7 @@ func (s *session) ExecuteSchemeQuery(
}
}
_, err = s.tableService.ExecuteSchemeQuery(ctx, &request)
+
return xerrors.WithStackTrace(err)
}
@@ -972,8 +986,8 @@ func (s *session) StreamReadTable(
opts ...options.ReadTableOption,
) (_ result.StreamResult, err error) {
var (
- onIntermediate = trace.TableOnSessionQueryStreamRead(s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ onDone = trace.TableOnSessionQueryStreamRead(s.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).StreamReadTable"),
s,
)
request = Ydb_Table.ReadTableRequest{
@@ -985,9 +999,7 @@ func (s *session) StreamReadTable(
)
defer func() {
a.Free()
- if err != nil {
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
- }
+ onDone(xerrors.HideEOF(err))
}()
for _, opt := range opts {
@@ -1001,6 +1013,7 @@ func (s *session) StreamReadTable(
stream, err = s.tableService.StreamReadTable(ctx, &request)
if err != nil {
cancel()
+
return nil, xerrors.WithStackTrace(err)
}
@@ -1010,9 +1023,6 @@ func (s *session) StreamReadTable(
stats *Ydb_TableStats.QueryStats,
err error,
) {
- defer func() {
- onIntermediate(xerrors.HideEOF(err))
- }()
select {
case <-ctx.Done():
return nil, nil, xerrors.WithStackTrace(ctx.Err())
@@ -1023,12 +1033,14 @@ func (s *session) StreamReadTable(
if result == nil || err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
+
return result.GetResultSet(), nil, nil
}
},
func(err error) error {
cancel()
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
+ onDone(xerrors.HideEOF(err))
+
return err
},
scanner.WithIgnoreTruncated(true), // stream read table always returns truncated flag on last result set
@@ -1038,7 +1050,7 @@ func (s *session) StreamReadTable(
func (s *session) ReadRows(
ctx context.Context,
path string,
- keys types.Value,
+ keys value.Value,
opts ...options.ReadRowsOption,
) (_ result.Result, err error) {
var (
@@ -1067,9 +1079,7 @@ func (s *session) ReadRows(
if response.GetStatus() != Ydb.StatusIds_SUCCESS {
return nil, xerrors.WithStackTrace(
- xerrors.Operation(
- xerrors.FromOperation(response),
- ),
+ xerrors.FromOperation(response),
)
}
@@ -1088,20 +1098,20 @@ func (s *session) ReadRows(
func (s *session) StreamExecuteScanQuery(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ parameters *params.Parameters,
opts ...options.ExecuteScanQueryOption,
) (_ result.StreamResult, err error) {
var (
- a = allocator.New()
- q = queryFromText(query)
- onIntermediate = trace.TableOnSessionQueryStreamExecute(
+ a = allocator.New()
+ q = queryFromText(query)
+ onDone = trace.TableOnSessionQueryStreamExecute(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
- s, q, params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).StreamExecuteScanQuery"),
+ s, q, parameters,
)
request = Ydb_Table.ExecuteScanQueryRequest{
Query: q.toYDB(a),
- Parameters: params.Params().ToYDB(a),
+ Parameters: parameters.ToYDB(a),
Mode: Ydb_Table.ExecuteScanQueryRequest_MODE_EXEC, // set default
}
stream Ydb_Table_V1.TableService_StreamExecuteScanQueryClient
@@ -1109,9 +1119,7 @@ func (s *session) StreamExecuteScanQuery(
)
defer func() {
a.Free()
- if err != nil {
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
- }
+ onDone(xerrors.HideEOF(err))
}()
for _, opt := range opts {
@@ -1125,6 +1133,7 @@ func (s *session) StreamExecuteScanQuery(
stream, err = s.tableService.StreamExecuteScanQuery(ctx, &request, callOptions...)
if err != nil {
cancel()
+
return nil, xerrors.WithStackTrace(err)
}
@@ -1134,9 +1143,6 @@ func (s *session) StreamExecuteScanQuery(
stats *Ydb_TableStats.QueryStats,
err error,
) {
- defer func() {
- onIntermediate(xerrors.HideEOF(err))
- }()
select {
case <-ctx.Done():
return nil, nil, xerrors.WithStackTrace(ctx.Err())
@@ -1147,12 +1153,14 @@ func (s *session) StreamExecuteScanQuery(
if result == nil || err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
+
return result.GetResultSet(), result.GetQueryStats(), nil
}
},
func(err error) error {
cancel()
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
+ onDone(xerrors.HideEOF(err))
+
return err
},
scanner.WithIgnoreTruncated(s.config.IgnoreTruncated()),
@@ -1161,7 +1169,7 @@ func (s *session) StreamExecuteScanQuery(
}
// BulkUpsert uploads given list of ydb struct values to the table.
-func (s *session) BulkUpsert(ctx context.Context, table string, rows types.Value,
+func (s *session) BulkUpsert(ctx context.Context, table string, rows value.Value,
opts ...options.BulkUpsertOption,
) (err error) {
var (
@@ -1169,7 +1177,7 @@ func (s *session) BulkUpsert(ctx context.Context, table string, rows types.Value
callOptions []grpc.CallOption
onDone = trace.TableOnSessionBulkUpsert(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).BulkUpsert"),
s,
)
)
@@ -1179,7 +1187,9 @@ func (s *session) BulkUpsert(ctx context.Context, table string, rows types.Value
}()
for _, opt := range opts {
- callOptions = append(callOptions, opt.ApplyBulkUpsertOption()...)
+ if opt != nil {
+ callOptions = append(callOptions, opt.ApplyBulkUpsertOption()...)
+ }
}
_, err = s.tableService.BulkUpsert(ctx,
@@ -1211,9 +1221,9 @@ func (s *session) BeginTransaction(
var (
result Ydb_Table.BeginTransactionResult
response *Ydb_Table.BeginTransactionResponse
- onDone = trace.TableOnSessionTransactionBegin(
+ onDone = trace.TableOnTxBegin(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).BeginTransaction"),
s,
)
)
@@ -1246,5 +1256,6 @@ func (s *session) BeginTransaction(
control: table.TxControl(table.WithTxID(result.GetTxMeta().GetId())),
}
tx.state.Store(txStateInitialized)
+
return tx, nil
}
diff --git a/internal/table/session_test.go b/internal/table/session_test.go
index d841c5fd4..006086369 100644
--- a/internal/table/session_test.go
+++ b/internal/table/session_test.go
@@ -22,12 +22,12 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
"github.com/ydb-platform/ydb-go-sdk/v3/testutil"
)
@@ -106,6 +106,7 @@ func TestSessionDescribeTable(t *testing.T) {
testutil.TableDescribeTable: func(interface{}) (proto.Message, error) {
r := &Ydb_Table.DescribeTableResult{}
proto.Merge(r, result)
+
return r, e
},
},
@@ -132,17 +133,17 @@ func TestSessionDescribeTable(t *testing.T) {
Columns: []options.Column{
{
Name: "testColumn",
- Type: types.Void(),
+ Type: types.NewVoid(),
Family: "testFamily",
},
},
KeyRanges: []options.KeyRange{
{
From: nil,
- To: types.Int64Value(100500),
+ To: value.Int64Value(100500),
},
{
- From: types.Int64Value(100500),
+ From: value.Int64Value(100500),
To: nil,
},
},
@@ -181,7 +182,7 @@ func TestSessionDescribeTable(t *testing.T) {
Columns: []*Ydb_Table.ColumnMeta{
{
Name: expect.Columns[0].Name,
- Type: value.TypeToYDB(expect.Columns[0].Type, a),
+ Type: types.TypeToYDB(expect.Columns[0].Type, a),
Family: "testFamily",
},
},
@@ -338,7 +339,7 @@ func TestSessionOperationModeOnExecuteDataQuery(t *testing.T) {
func(t *testing.T) {
for _, srcDst := range fromTo {
t.Run(srcDst.srcMode.String()+"->"+srcDst.dstMode.String(), func(t *testing.T) {
- client, err := New(context.Background(), testutil.NewBalancer(
+ client := New(context.Background(), testutil.NewBalancer(
testutil.WithInvokeHandlers(
testutil.InvokeHandlers{
testutil.TableExecuteDataQuery: func(interface{}) (proto.Message, error) {
@@ -381,7 +382,6 @@ func TestSessionOperationModeOnExecuteDataQuery(t *testing.T) {
},
),
), config.New())
- require.NoError(t, err)
ctx, cancel := xcontext.WithTimeout(
context.Background(),
time.Second,
@@ -396,7 +396,7 @@ func TestSessionOperationModeOnExecuteDataQuery(t *testing.T) {
}
func TestCreateTableRegression(t *testing.T) {
- client, err := New(context.Background(), testutil.NewBalancer(
+ client := New(context.Background(), testutil.NewBalancer(
testutil.WithInvokeHandlers(
testutil.InvokeHandlers{
testutil.TableCreateSession: func(request interface{}) (proto.Message, error) {
@@ -466,27 +466,26 @@ func TestCreateTableRegression(t *testing.T) {
//nolint:revive
return nil, fmt.Errorf("proto's not equal: \n\nact: %v\n\nexp: %s\n\n", act, exp)
}
+
return &Ydb_Table.CreateTableResponse{}, nil
},
},
),
), config.New())
- require.NoError(t, err)
-
ctx, cancel := xcontext.WithTimeout(
context.Background(),
time.Second,
)
defer cancel()
- err = client.Do(ctx, func(ctx context.Context, s table.Session) error {
+ err := client.Do(ctx, func(ctx context.Context, s table.Session) error {
return s.CreateTable(ctx, "episodes",
- options.WithColumn("series_id", types.Optional(types.TypeUint64)),
- options.WithColumn("season_id", types.Optional(types.TypeUint64)),
- options.WithColumn("episode_id", types.Optional(types.TypeUint64)),
- options.WithColumn("title", types.Optional(types.TypeText)),
- options.WithColumn("air_date", types.Optional(types.TypeUint64)),
+ options.WithColumn("series_id", types.NewOptional(types.Uint64)),
+ options.WithColumn("season_id", types.NewOptional(types.Uint64)),
+ options.WithColumn("episode_id", types.NewOptional(types.Uint64)),
+ options.WithColumn("title", types.NewOptional(types.Text)),
+ options.WithColumn("air_date", types.NewOptional(types.Uint64)),
options.WithPrimaryKeyColumn("series_id", "season_id", "episode_id"),
options.WithAttribute("attr", "attr_value"),
)
@@ -496,7 +495,7 @@ func TestCreateTableRegression(t *testing.T) {
}
func TestDescribeTableRegression(t *testing.T) {
- client, err := New(context.Background(), testutil.NewBalancer(
+ client := New(context.Background(), testutil.NewBalancer(
testutil.WithInvokeHandlers(
testutil.InvokeHandlers{
testutil.TableCreateSession: func(request interface{}) (proto.Message, error) {
@@ -565,8 +564,6 @@ func TestDescribeTableRegression(t *testing.T) {
),
), config.New())
- require.NoError(t, err)
-
ctx, cancel := xcontext.WithTimeout(
context.Background(),
time.Second,
@@ -575,8 +572,9 @@ func TestDescribeTableRegression(t *testing.T) {
var act options.Description
- err = client.Do(ctx, func(ctx context.Context, s table.Session) (err error) {
+ err := client.Do(ctx, func(ctx context.Context, s table.Session) (err error) {
act, err = s.DescribeTable(ctx, "episodes")
+
return err
})
@@ -587,23 +585,23 @@ func TestDescribeTableRegression(t *testing.T) {
Columns: []options.Column{
{
Name: "series_id",
- Type: types.Optional(types.TypeUint64),
+ Type: types.NewOptional(types.Uint64),
},
{
Name: "season_id",
- Type: types.Optional(types.TypeUint64),
+ Type: types.NewOptional(types.Uint64),
},
{
Name: "episode_id",
- Type: types.Optional(types.TypeUint64),
+ Type: types.NewOptional(types.Uint64),
},
{
Name: "title",
- Type: types.Optional(types.TypeText),
+ Type: types.NewOptional(types.Text),
},
{
Name: "air_date",
- Type: types.Optional(types.TypeUint64),
+ Type: types.NewOptional(types.Uint64),
},
},
KeyRanges: []options.KeyRange{
@@ -637,6 +635,7 @@ func (mock *copyTablesMock) CopyTables(
if in.String() == mock.String() {
return &Ydb_Table.CopyTablesResponse{}, nil
}
+
return nil, fmt.Errorf("%w: %s, exp: %s", errUnexpectedRequest, in, mock.String())
}
diff --git a/internal/table/statement.go b/internal/table/statement.go
index e59f07b5a..eb797e2ef 100644
--- a/internal/table/statement.go
+++ b/internal/table/statement.go
@@ -9,6 +9,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
@@ -26,7 +27,7 @@ type statement struct {
// Execute executes prepared data query.
func (s *statement) Execute(
ctx context.Context, txControl *table.TransactionControl,
- params *table.QueryParameters,
+ parameters *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (
txr table.Transaction, r result.Result, err error,
@@ -43,10 +44,10 @@ func (s *statement) Execute(
request.SessionId = s.session.id
request.TxControl = txControl.Desc()
- request.Parameters = params.Params().ToYDB(a)
+ request.Parameters = parameters.ToYDB(a)
request.Query = s.query.toYDB(a)
request.QueryCachePolicy = a.TableQueryCachePolicy()
- request.QueryCachePolicy.KeepInCache = len(params.Params()) > 0
+ request.QueryCachePolicy.KeepInCache = len(request.Parameters) > 0
request.OperationParams = operation.Params(ctx,
s.session.config.OperationTimeout(),
s.session.config.OperationCancelAfter(),
@@ -61,8 +62,8 @@ func (s *statement) Execute(
onDone := trace.TableOnSessionQueryExecute(
s.session.config.Trace(), &ctx,
- stack.FunctionID(""),
- s.session, s.query, params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*statement).Execute"),
+ s.session, s.query, parameters,
request.QueryCachePolicy.GetKeepInCache(),
)
defer func() {
@@ -84,6 +85,7 @@ func (s *statement) execute(
if err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
+
return s.session.executeQueryResult(res, txControl, request.IgnoreTruncated)
}
diff --git a/internal/table/transaction.go b/internal/table/transaction.go
index 180784c3a..a07576196 100644
--- a/internal/table/transaction.go
+++ b/internal/table/transaction.go
@@ -3,14 +3,15 @@ package table
import (
"context"
"fmt"
+ "sync/atomic"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/scanner"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
@@ -24,7 +25,7 @@ var (
)
type txState struct {
- rawVal xatomic.Uint32
+ rawVal atomic.Uint32
}
func (s *txState) Load() txStateEnum {
@@ -57,13 +58,13 @@ func (tx *transaction) ID() string {
// Execute executes query represented by text within transaction tx.
func (tx *transaction) Execute(
ctx context.Context,
- query string, params *table.QueryParameters,
+ query string, parameters *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (r result.Result, err error) {
- onDone := trace.TableOnSessionTransactionExecute(
+ onDone := trace.TableOnTxExecute(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
- tx.s, tx, queryFromText(query), params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).Execute"),
+ tx.s, tx, queryFromText(query), parameters,
)
defer func() {
onDone(r, err)
@@ -75,12 +76,12 @@ func (tx *transaction) Execute(
case txStateRollbacked:
return nil, xerrors.WithStackTrace(errTxRollbackedEarly)
default:
- _, r, err = tx.s.Execute(ctx, tx.control, query, params, opts...)
+ _, r, err = tx.s.Execute(ctx, tx.control, query, parameters, opts...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- if tx.control.Desc().CommitTx {
+ if tx.control.Desc().GetCommitTx() {
tx.state.Store(txStateCommitted)
}
@@ -91,19 +92,16 @@ func (tx *transaction) Execute(
// ExecuteStatement executes prepared statement stmt within transaction tx.
func (tx *transaction) ExecuteStatement(
ctx context.Context,
- stmt table.Statement, params *table.QueryParameters,
+ stmt table.Statement, parameters *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (r result.Result, err error) {
- if params == nil {
- params = table.NewQueryParameters()
- }
a := allocator.New()
defer a.Free()
- onDone := trace.TableOnSessionTransactionExecuteStatement(
+ onDone := trace.TableOnTxExecuteStatement(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
- tx.s, tx, stmt.(*statement).query, params,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).ExecuteStatement"),
+ tx.s, tx, stmt.(*statement).query, parameters,
)
defer func() {
onDone(r, err)
@@ -115,12 +113,12 @@ func (tx *transaction) ExecuteStatement(
case txStateRollbacked:
return nil, xerrors.WithStackTrace(errTxRollbackedEarly)
default:
- _, r, err = stmt.Execute(ctx, tx.control, params, opts...)
+ _, r, err = stmt.Execute(ctx, tx.control, parameters, opts...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- if tx.control.Desc().CommitTx {
+ if tx.control.Desc().GetCommitTx() {
tx.state.Store(txStateCommitted)
}
@@ -133,9 +131,9 @@ func (tx *transaction) CommitTx(
ctx context.Context,
opts ...options.CommitTransactionOption,
) (r result.Result, err error) {
- onDone := trace.TableOnSessionTransactionCommit(
+ onDone := trace.TableOnTxCommit(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).CommitTx"),
tx.s, tx,
)
defer func() {
@@ -191,9 +189,9 @@ func (tx *transaction) CommitTx(
// Rollback performs a rollback of the specified active transaction.
func (tx *transaction) Rollback(ctx context.Context) (err error) {
- onDone := trace.TableOnSessionTransactionRollback(
+ onDone := trace.TableOnTxRollback(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).Rollback"),
tx.s, tx,
)
defer func() {
diff --git a/internal/table/transaction_test.go b/internal/table/transaction_test.go
index c08d19e25..cc4e88489 100644
--- a/internal/table/transaction_test.go
+++ b/internal/table/transaction_test.go
@@ -31,6 +31,7 @@ func TestTxSkipRollbackForCommitted(t *testing.T) {
t.Fatalf("cannot cast request '%T' to *Ydb_Table.BeginTransactionRequest", request)
}
begin++
+
return &Ydb_Table.BeginTransactionResult{
TxMeta: &Ydb_Table.TransactionMeta{
Id: "",
@@ -43,6 +44,7 @@ func TestTxSkipRollbackForCommitted(t *testing.T) {
t.Fatalf("cannot cast request '%T' to *Ydb_Table.CommitTransactionRequest", request)
}
commit++
+
return &Ydb_Table.CommitTransactionResult{}, nil
},
testutil.TableRollbackTransaction: func(request interface{}) (proto.Message, error) {
@@ -51,6 +53,7 @@ func TestTxSkipRollbackForCommitted(t *testing.T) {
t.Fatalf("cannot cast request '%T' to *Ydb_Table.RollbackTransactionRequest", request)
}
rollback++
+
return &Ydb_Table.RollbackTransactionResponse{
Operation: &Ydb_Operations.Operation{
Ready: true,
diff --git a/internal/table/ttl.go b/internal/table/ttl.go
index c734847d9..fd3ad945e 100644
--- a/internal/table/ttl.go
+++ b/internal/table/ttl.go
@@ -10,22 +10,23 @@ func NewTimeToLiveSettings(settings *Ydb_Table.TtlSettings) *options.TimeToLiveS
if settings == nil {
return nil
}
- switch mode := settings.Mode.(type) {
+ switch mode := settings.GetMode().(type) {
case *Ydb_Table.TtlSettings_DateTypeColumn:
return &options.TimeToLiveSettings{
- ColumnName: mode.DateTypeColumn.ColumnName,
- ExpireAfterSeconds: mode.DateTypeColumn.ExpireAfterSeconds,
+ ColumnName: mode.DateTypeColumn.GetColumnName(),
+ ExpireAfterSeconds: mode.DateTypeColumn.GetExpireAfterSeconds(),
Mode: options.TimeToLiveModeDateType,
}
case *Ydb_Table.TtlSettings_ValueSinceUnixEpoch:
return &options.TimeToLiveSettings{
- ColumnName: mode.ValueSinceUnixEpoch.ColumnName,
- ColumnUnit: timeToLiveUnit(mode.ValueSinceUnixEpoch.ColumnUnit),
- ExpireAfterSeconds: mode.ValueSinceUnixEpoch.ExpireAfterSeconds,
+ ColumnName: mode.ValueSinceUnixEpoch.GetColumnName(),
+ ColumnUnit: timeToLiveUnit(mode.ValueSinceUnixEpoch.GetColumnUnit()),
+ ExpireAfterSeconds: mode.ValueSinceUnixEpoch.GetExpireAfterSeconds(),
Mode: options.TimeToLiveModeValueSinceUnixEpoch,
}
}
+
return nil
}
@@ -45,5 +46,6 @@ func timeToLiveUnit(unit Ydb_Table.ValueSinceUnixEpochModeSettings_Unit) *option
default:
panic("ydb: unknown Ydb unit for value since epoch")
}
+
return &res
}
diff --git a/internal/topic/retriable_error.go b/internal/topic/retriable_error.go
index 5d08b5087..23ef3c49c 100644
--- a/internal/topic/retriable_error.go
+++ b/internal/topic/retriable_error.go
@@ -7,12 +7,14 @@ import (
"time"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/backoff"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
)
const (
- DefaultStartTimeout = time.Minute
+ DefaultStartTimeout = time.Minute
+ connectionEstablishedTimeout = time.Minute
)
type RetrySettings struct {
@@ -44,6 +46,10 @@ var (
func CheckResetReconnectionCounters(lastTry, now time.Time, connectionTimeout time.Duration) bool {
const resetAttemptEmpiricalCoefficient = 10
+ if connectionTimeout == value.InfiniteDuration {
+ return now.Sub(lastTry) > connectionEstablishedTimeout
+ }
+
return now.Sub(lastTry) > connectionTimeout*resetAttemptEmpiricalCoefficient
}
@@ -87,9 +93,10 @@ func CheckRetryMode(err error, settings RetrySettings, retriesDuration time.Dura
return nil, false
}
- if mode.BackoffType() == backoff.TypeFast {
+ switch mode.BackoffType() {
+ case backoff.TypeFast:
return backoff.Fast, true
+ default:
+ return backoff.Slow, true
}
-
- return backoff.Slow, true
}
diff --git a/internal/topic/retriable_error_test.go b/internal/topic/retriable_error_test.go
index 79e8e7128..9de4b2c00 100644
--- a/internal/topic/retriable_error_test.go
+++ b/internal/topic/retriable_error_test.go
@@ -12,6 +12,7 @@ import (
grpcStatus "google.golang.org/grpc/status"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/backoff"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
@@ -232,3 +233,45 @@ func TestCheckRetryMode(t *testing.T) {
})
}
}
+
+func TestCheckResetReconnectionCounters(t *testing.T) {
+ now := time.Now()
+ table := []struct {
+ name string
+ lastTry time.Time
+ connectionTimeout time.Duration
+ shouldReset bool
+ }{
+ {
+ name: "RecentLastTryWithInfiniteConnectionTimeout",
+ lastTry: now.Add(-30 * time.Second),
+ connectionTimeout: value.InfiniteDuration,
+ shouldReset: false,
+ },
+ {
+ name: "OldLastTryWithInfiniteConnectionTimeout",
+ lastTry: now.Add(-30 * time.Minute),
+ connectionTimeout: value.InfiniteDuration,
+ shouldReset: true,
+ },
+ {
+ name: "LastTryLessThanConnectionTimeout",
+ lastTry: now.Add(-30 * time.Second),
+ connectionTimeout: time.Minute,
+ shouldReset: false,
+ },
+ {
+ name: "LastTryGreaterThanConnectionTimeout",
+ lastTry: now.Add(-time.Hour),
+ connectionTimeout: time.Minute,
+ shouldReset: true,
+ },
+ }
+
+ for _, test := range table {
+ t.Run(test.name, func(t *testing.T) {
+ shouldReset := CheckResetReconnectionCounters(test.lastTry, now, test.connectionTimeout)
+ require.Equal(t, test.shouldReset, shouldReset)
+ })
+ }
+}
diff --git a/internal/topic/topicclientinternal/client.go b/internal/topic/topicclientinternal/client.go
index d774a30fb..2318d97b1 100644
--- a/internal/topic/topicclientinternal/client.go
+++ b/internal/topic/topicclientinternal/client.go
@@ -32,7 +32,7 @@ func New(
conn grpc.ClientConnInterface,
cred credentials.Credentials,
opts ...topicoptions.TopicOption,
-) (*Client, error) {
+) *Client {
rawClient := rawtopic.NewClient(Ydb_Topic_V1.NewTopicServiceClient(conn))
cfg := newTopicConfig(opts...)
@@ -45,18 +45,19 @@ func New(
cred: cred,
defaultOperationParams: defaultOperationParams,
rawClient: rawClient,
- }, nil
+ }
}
func newTopicConfig(opts ...topicoptions.TopicOption) topic.Config {
c := topic.Config{
Trace: &trace.Topic{},
}
- for _, o := range opts {
- if o != nil {
- o(&c)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&c)
}
}
+
return c
}
@@ -70,14 +71,15 @@ func (c *Client) Alter(ctx context.Context, path string, opts ...topicoptions.Al
req := &rawtopic.AlterTopicRequest{}
req.OperationParams = c.defaultOperationParams
req.Path = path
- for _, o := range opts {
- if o != nil {
- o.ApplyAlterOption(req)
+ for _, opt := range opts {
+ if opt != nil {
+ opt.ApplyAlterOption(req)
}
}
call := func(ctx context.Context) error {
_, alterErr := c.rawClient.AlterTopic(ctx, req)
+
return alterErr
}
@@ -101,14 +103,15 @@ func (c *Client) Create(
req.OperationParams = c.defaultOperationParams
req.Path = path
- for _, o := range opts {
- if o != nil {
- o.ApplyCreateOption(req)
+ for _, opt := range opts {
+ if opt != nil {
+ opt.ApplyCreateOption(req)
}
}
call := func(ctx context.Context) error {
_, createErr := c.rawClient.CreateTopic(ctx, req)
+
return createErr
}
@@ -133,9 +136,9 @@ func (c *Client) Describe(
Path: path,
}
- for _, o := range opts {
- if o != nil {
- o(&req)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&req)
}
}
@@ -143,6 +146,7 @@ func (c *Client) Describe(
call := func(ctx context.Context) (describeErr error) {
rawRes, describeErr = c.rawClient.DescribeTopic(ctx, req)
+
return describeErr
}
@@ -162,6 +166,7 @@ func (c *Client) Describe(
}
res.FromRaw(&rawRes)
+
return res, nil
}
@@ -171,14 +176,15 @@ func (c *Client) Drop(ctx context.Context, path string, opts ...topicoptions.Dro
req.OperationParams = c.defaultOperationParams
req.Path = path
- for _, o := range opts {
- if o != nil {
- o.ApplyDropOption(&req)
+ for _, opt := range opts {
+ if opt != nil {
+ opt.ApplyDropOption(&req)
}
}
call := func(ctx context.Context) error {
_, removeErr := c.rawClient.DropTopic(ctx, req)
+
return removeErr
}
@@ -215,6 +221,7 @@ func (c *Client) StartReader(
internalReader := topicreaderinternal.NewReader(connector, consumer, readSelectors, opts...)
trace.TopicOnReaderStart(internalReader.Tracer(), internalReader.ID(), consumer)
+
return topicreader.NewReader(internalReader), nil
}
@@ -240,5 +247,6 @@ func (c *Client) StartWriter(topicPath string, opts ...topicoptions.WriterOption
if err != nil {
return nil, err
}
+
return topicwriter.NewWriter(writer), nil
}
diff --git a/internal/topic/topicreaderinternal/batch.go b/internal/topic/topicreaderinternal/batch.go
index 14283d0fe..e8e00ad01 100644
--- a/internal/topic/topicreaderinternal/batch.go
+++ b/internal/topic/topicreaderinternal/batch.go
@@ -143,6 +143,7 @@ func (m *PublicBatch) append(b *PublicBatch) (*PublicBatch, error) {
res.Messages = append(res.Messages, b.Messages...)
res.commitRange.commitOffsetEnd = b.commitRange.commitOffsetEnd
+
return res, nil
}
@@ -157,6 +158,7 @@ func (m *PublicBatch) cutMessages(count int) (head, rest *PublicBatch) {
// explicit 0 need for prevent typos, when type slice[count:count] instead of slice[:count:count]
head, _ = newBatch(m.commitRange.partitionSession, m.Messages[0:count:count])
rest, _ = newBatch(m.commitRange.partitionSession, m.Messages[count:])
+
return head, rest
}
}
@@ -175,9 +177,11 @@ func splitBytesByMessagesInBatches(batches []*PublicBatch, totalBytesCount int)
case want >= restBytes:
res := restBytes
restBytes = 0
+
return res
default:
restBytes -= want
+
return want
}
}
diff --git a/internal/topic/topicreaderinternal/batcher.go b/internal/topic/topicreaderinternal/batcher.go
index 1d6b7ee27..8eaa5eb6b 100644
--- a/internal/topic/topicreaderinternal/batcher.go
+++ b/internal/topic/topicreaderinternal/batcher.go
@@ -46,6 +46,7 @@ func (b *batcher) Close(err error) error {
b.closed = true
b.closeErr = err
close(b.closeChan)
+
return nil
}
@@ -126,6 +127,7 @@ func (o batcherGetOptions) cutBatchItemsHead(items batcherMessageOrderItems) (
head = newBatcherItemBatch(batchHead)
rest = items.ReplaceHeadItem(newBatcherItemBatch(batchRest))
+
return head, rest, true
}
@@ -146,6 +148,7 @@ func (o batcherGetOptions) splitBatch(batch *PublicBatch) (head, rest *PublicBat
}
head, rest = batch.cutMessages(o.MaxCount)
+
return head, rest, true
}
@@ -173,7 +176,8 @@ func (b *batcher) Pop(ctx context.Context, opts batcherGetOptions) (_ batcherMes
findRes = b.findNeedLock(opts)
if findRes.Ok {
- b.applyNeedLock(findRes)
+ b.applyNeedLock(&findRes)
+
return
}
})
@@ -271,10 +275,11 @@ func (b *batcher) applyForceFlagToOptions(options batcherGetOptions) batcherGetO
res := options
res.MinCount = 1
+
return res
}
-func (b *batcher) applyNeedLock(res batcherResultCandidate) {
+func (b *batcher) applyNeedLock(res *batcherResultCandidate) {
if res.Rest.IsEmpty() && res.WaiterIndex >= 0 {
delete(b.messages, res.Key)
} else {
@@ -310,6 +315,7 @@ func (items batcherMessageOrderItems) Append(item batcherMessageOrderItem) (batc
} else {
return nil, err
}
+
return items, nil
}
@@ -328,6 +334,7 @@ func (items batcherMessageOrderItems) ReplaceHeadItem(item batcherMessageOrderIt
res := make(batcherMessageOrderItems, len(items))
res[0] = item
copy(res[1:], items[1:])
+
return res
}
diff --git a/internal/topic/topicreaderinternal/batcher_test.go b/internal/topic/topicreaderinternal/batcher_test.go
index e048ef9f2..c926e7076 100644
--- a/internal/topic/topicreaderinternal/batcher_test.go
+++ b/internal/topic/topicreaderinternal/batcher_test.go
@@ -3,6 +3,7 @@ package topicreaderinternal
import (
"context"
"errors"
+ "sync/atomic"
"testing"
"time"
@@ -10,7 +11,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicreader"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
)
@@ -282,7 +282,7 @@ func TestBatcher_PopMinIgnored(t *testing.T) {
},
}}))
- var IgnoreMinRestrictionsOnNextPopDone xatomic.Int64
+ var IgnoreMinRestrictionsOnNextPopDone atomic.Int64
go func() {
defer IgnoreMinRestrictionsOnNextPopDone.Add(1)
@@ -407,7 +407,7 @@ func TestBatcher_Apply(t *testing.T) {
Key: session,
Rest: batcherMessageOrderItems{newBatcherItemBatch(batch)},
}
- b.applyNeedLock(foundRes)
+ b.applyNeedLock(&foundRes)
expectedMap := batcherMessagesMap{session: batcherMessageOrderItems{newBatcherItemBatch(batch)}}
require.Equal(t, expectedMap, b.messages)
@@ -426,7 +426,7 @@ func TestBatcher_Apply(t *testing.T) {
b.messages = batcherMessagesMap{session: batcherMessageOrderItems{newBatcherItemBatch(batch)}}
- b.applyNeedLock(foundRes)
+ b.applyNeedLock(&foundRes)
require.Empty(t, b.messages)
})
@@ -502,5 +502,6 @@ func mustNewBatch(session *partitionSession, messages []*PublicMessage) *PublicB
if err != nil {
panic(err)
}
+
return batch
}
diff --git a/internal/topic/topicreaderinternal/commit_range.go b/internal/topic/topicreaderinternal/commit_range.go
index 0f1554780..c744cd49b 100644
--- a/internal/topic/topicreaderinternal/commit_range.go
+++ b/internal/topic/topicreaderinternal/commit_range.go
@@ -32,6 +32,7 @@ func (r *CommitRanges) GetCommitsInfo() []trace.TopicReaderStreamCommitInfo {
EndOffset: r.ranges[i].commitOffsetEnd.ToInt64(),
}
}
+
return res
}
@@ -45,6 +46,7 @@ func NewCommitRangesFromPublicCommits(ranges []PublicCommitRange) CommitRanges {
for i := 0; i < len(res.ranges); i++ {
res.ranges[i] = ranges[i].priv
}
+
return res
}
@@ -84,6 +86,7 @@ func (r *CommitRanges) toPartitionsOffsets() []rawtopicreader.PartitionCommitOff
}
r.optimize()
+
return r.toRawPartitionCommitOffset()
}
@@ -149,6 +152,7 @@ func (r *CommitRanges) toRawPartitionCommitOffset() []rawtopicreader.PartitionCo
}
partition.Offsets = append(partition.Offsets, offsetsRange)
}
+
return partitionOffsets
}
diff --git a/internal/topic/topicreaderinternal/commit_range_test.go b/internal/topic/topicreaderinternal/commit_range_test.go
index d0d95cb60..2ba8e1e02 100644
--- a/internal/topic/topicreaderinternal/commit_range_test.go
+++ b/internal/topic/topicreaderinternal/commit_range_test.go
@@ -284,5 +284,6 @@ func TestCommitsToRawPartitionCommitOffset(t *testing.T) {
func testNewCommitRanges(commitable ...PublicCommitRangeGetter) *CommitRanges {
var res CommitRanges
res.Append(commitable...)
+
return &res
}
diff --git a/internal/topic/topicreaderinternal/committer.go b/internal/topic/topicreaderinternal/committer.go
index 4f614ce14..c3f22849f 100644
--- a/internal/topic/topicreaderinternal/committer.go
+++ b/internal/topic/topicreaderinternal/committer.go
@@ -62,6 +62,7 @@ func newCommitter(tracer *trace.Topic, lifeContext context.Context, mode PublicC
}
res.initChannels()
res.start()
+
return res
}
@@ -100,6 +101,7 @@ func (c *committer) pushCommit(commitRange commitRange) (commitWaiter, error) {
c.m.WithLock(func() {
if err := c.backgroundWorker.Context().Err(); err != nil {
resErr = err
+
return
}
@@ -170,6 +172,7 @@ func (c *committer) waitSendTrigger(ctx context.Context) {
case <-ctxDone:
case <-finish:
}
+
return
}
@@ -260,6 +263,7 @@ var commitWaiterLastID int64
func newCommitWaiter(session *partitionSession, endOffset rawtopicreader.Offset) commitWaiter {
id := atomic.AddInt64(&commitWaiterLastID, 1)
+
return commitWaiter{
ID: id,
Session: session,
@@ -272,5 +276,6 @@ func sendCommitMessage(send sendMessageToServerFunc, batch CommitRanges) error {
req := &rawtopicreader.CommitOffsetRequest{
CommitOffsets: batch.toPartitionsOffsets(),
}
+
return send(req)
}
diff --git a/internal/topic/topicreaderinternal/committer_test.go b/internal/topic/topicreaderinternal/committer_test.go
index b9545fe1e..7bf444d62 100644
--- a/internal/topic/topicreaderinternal/committer_test.go
+++ b/internal/topic/topicreaderinternal/committer_test.go
@@ -23,6 +23,7 @@ func TestCommitterCommit(t *testing.T) {
c := newTestCommitter(ctx, t)
c.send = func(msg rawtopicreader.ClientMessage) error {
t.Fatalf("must not call")
+
return nil
}
@@ -65,6 +66,7 @@ func TestCommitterCommitAsync(t *testing.T) {
CommitOffsets: testNewCommitRanges(&cRange).toPartitionsOffsets(),
},
msg)
+
return nil
}
require.NoError(t, c.Commit(ctx, cRange))
@@ -97,6 +99,7 @@ func TestCommitterCommitSync(t *testing.T) {
},
msg)
c.OnCommitNotify(session, cRange.commitOffsetEnd)
+
return nil
}
require.NoError(t, c.Commit(ctx, cRange))
@@ -121,6 +124,7 @@ func TestCommitterCommitSync(t *testing.T) {
c.mode = CommitModeSync
c.send = func(msg rawtopicreader.ClientMessage) error {
close(commitSended)
+
return nil
}
@@ -201,6 +205,7 @@ func TestCommitterBuffer(t *testing.T) {
c.clock = clock
c.send = func(msg rawtopicreader.ClientMessage) error {
close(sendCalled)
+
return nil
}
@@ -229,6 +234,7 @@ func TestCommitterBuffer(t *testing.T) {
commitMess := msg.(*rawtopicreader.CommitOffsetRequest)
require.Len(t, commitMess.CommitOffsets, 2)
close(sendCalled)
+
return nil
}
@@ -261,6 +267,7 @@ func TestCommitterBuffer(t *testing.T) {
commitMess := msg.(*rawtopicreader.CommitOffsetRequest)
require.Len(t, commitMess.CommitOffsets, 4)
close(sendCalled)
+
return nil
}
c.commits.appendCommitRanges([]commitRange{
@@ -295,6 +302,7 @@ func TestCommitterBuffer(t *testing.T) {
commitMess := msg.(*rawtopicreader.CommitOffsetRequest)
require.Len(t, commitMess.CommitOffsets, 4)
close(sendCalled)
+
return nil
}
@@ -330,6 +338,7 @@ func TestCommitterBuffer(t *testing.T) {
sendCalled := make(empty.Chan)
c.send = func(msg rawtopicreader.ClientMessage) error {
close(sendCalled)
+
return nil
}
_, err := c.pushCommit(commitRange{partitionSession: &partitionSession{}})
@@ -344,6 +353,7 @@ func TestCommitterBuffer(t *testing.T) {
c := newTestCommitter(ctx, t)
c.send = func(msg rawtopicreader.ClientMessage) error {
t.Fatal()
+
return nil
}
c.commitLoopSignal <- empty.Struct{} // to buffer
@@ -357,6 +367,7 @@ func TestCommitterBuffer(t *testing.T) {
sendCalled := false
c.send = func(msg rawtopicreader.ClientMessage) error {
sendCalled = true
+
return nil
}
c.commits.appendCommitRange(commitRange{partitionSession: &partitionSession{}})
@@ -374,5 +385,6 @@ func newTestCommitter(ctx context.Context, t testing.TB) *committer {
require.ErrorIs(t, err, background.ErrAlreadyClosed)
}
})
+
return res
}
diff --git a/internal/topic/topicreaderinternal/decoders.go b/internal/topic/topicreaderinternal/decoders.go
index 21456e97f..87773cdc7 100644
--- a/internal/topic/topicreaderinternal/decoders.go
+++ b/internal/topic/topicreaderinternal/decoders.go
@@ -34,8 +34,9 @@ func (m *decoderMap) Decode(codec rawtopiccommon.Codec, input io.Reader) (io.Rea
if f := m.m[codec]; f != nil {
return f(input)
}
+
return nil, xerrors.WithStackTrace(xerrors.Wrap(
- fmt.Errorf("ydb: failed decompress message with codec %v: %w", codec, PublicErrUnexpectedCodec),
+ fmt.Errorf("ydb: failed decompress message with codec %v: %w", codec, ErrPublicUnexpectedCodec),
))
}
diff --git a/internal/topic/topicreaderinternal/message.go b/internal/topic/topicreaderinternal/message.go
index 57aa89c5a..13cc98f0c 100644
--- a/internal/topic/topicreaderinternal/message.go
+++ b/internal/topic/topicreaderinternal/message.go
@@ -9,14 +9,13 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopiccommon"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xbytes"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
var errMessageWasReadEarly = xerrors.Wrap(errors.New("ydb: message was read early"))
-// PublicErrUnexpectedCodec return when try to read message content with unknown codec
-var PublicErrUnexpectedCodec = errors.New("unexpected codec") //nolint:revive,stylecheck
+// ErrPublicUnexpectedCodec return when try to read message content with unknown codec
+var ErrPublicUnexpectedCodec = errors.New("unexpected codec")
// PublicMessage is representation of topic message
type PublicMessage struct {
@@ -63,6 +62,7 @@ func (m *PublicMessage) UnmarshalTo(dst PublicMessageContentUnmarshaler) error {
}
m.dataConsumed = true
+
return callbackOnReaderContent(globalReadMessagePool, m, m.UncompressedSize, dst)
}
@@ -71,6 +71,7 @@ func (m *PublicMessage) UnmarshalTo(dst PublicMessageContentUnmarshaler) error {
// return topicreader.UnexpectedCodec if message compressed with unknown codec
func (m *PublicMessage) Read(p []byte) (n int, err error) {
m.dataConsumed = true
+
return m.data.Read(p)
}
@@ -108,6 +109,7 @@ type PublicMessageBuilder struct {
func NewPublicMessageBuilder() *PublicMessageBuilder {
res := &PublicMessageBuilder{}
res.initMessage()
+
return res
}
@@ -128,50 +130,58 @@ func (pmb *PublicMessageBuilder) initMessage() {
// Seqno set message Seqno
func (pmb *PublicMessageBuilder) Seqno(seqNo int64) *PublicMessageBuilder {
pmb.mess.SeqNo = seqNo
+
return pmb
}
// CreatedAt set message CreatedAt
func (pmb *PublicMessageBuilder) CreatedAt(createdAt time.Time) *PublicMessageBuilder {
pmb.mess.CreatedAt = createdAt
+
return pmb
}
func (pmb *PublicMessageBuilder) Metadata(metadata map[string][]byte) *PublicMessageBuilder {
pmb.mess.Metadata = make(map[string][]byte, len(metadata))
for key, val := range metadata {
- pmb.mess.Metadata[key] = xbytes.Clone(val)
+ pmb.mess.Metadata[key] = bytes.Clone(val)
}
+
return pmb
}
// MessageGroupID set message MessageGroupID
func (pmb *PublicMessageBuilder) MessageGroupID(messageGroupID string) *PublicMessageBuilder {
pmb.mess.MessageGroupID = messageGroupID
+
return pmb
}
// WriteSessionMetadata set message WriteSessionMetadata
func (pmb *PublicMessageBuilder) WriteSessionMetadata(writeSessionMetadata map[string]string) *PublicMessageBuilder {
pmb.mess.WriteSessionMetadata = writeSessionMetadata
+
return pmb
}
// Offset set message Offset
func (pmb *PublicMessageBuilder) Offset(offset int64) *PublicMessageBuilder {
pmb.mess.Offset = offset
+
return pmb
}
// WrittenAt set message WrittenAt
func (pmb *PublicMessageBuilder) WrittenAt(writtenAt time.Time) *PublicMessageBuilder {
pmb.mess.WrittenAt = writtenAt
+
return pmb
}
// ProducerID set message ProducerID
func (pmb *PublicMessageBuilder) ProducerID(producerID string) *PublicMessageBuilder {
pmb.mess.ProducerID = producerID
+
return pmb
}
@@ -183,12 +193,14 @@ func (pmb *PublicMessageBuilder) DataAndUncompressedSize(data []byte) *PublicMes
pmb.mess.dataConsumed = false
pmb.mess.rawDataLen = len(copyData)
pmb.mess.UncompressedSize = len(copyData)
+
return pmb
}
// UncompressedSize set message UncompressedSize
func (pmb *PublicMessageBuilder) UncompressedSize(uncompressedSize int) *PublicMessageBuilder {
pmb.mess.UncompressedSize = uncompressedSize
+
return pmb
}
@@ -211,5 +223,6 @@ func (pmb *PublicMessageBuilder) PartitionID(partitionID int64) {
func (pmb *PublicMessageBuilder) Build() *PublicMessage {
mess := pmb.mess
pmb.initMessage()
+
return mess
}
diff --git a/internal/topic/topicreaderinternal/message_content_pool.go b/internal/topic/topicreaderinternal/message_content_pool.go
index 5554cf17b..73b561cae 100644
--- a/internal/topic/topicreaderinternal/message_content_pool.go
+++ b/internal/topic/topicreaderinternal/message_content_pool.go
@@ -63,5 +63,6 @@ func callbackOnReaderContent(
if err := consumer.UnmarshalYDBTopicMessage(buf.Bytes()); err != nil {
return xerrors.WithStackTrace(fmt.Errorf("ydb: error unmarshal data: %w", err))
}
+
return nil
}
diff --git a/internal/topic/topicreaderinternal/message_content_pool_test.go b/internal/topic/topicreaderinternal/message_content_pool_test.go
index 63b13df97..60a6477f5 100644
--- a/internal/topic/topicreaderinternal/message_content_pool_test.go
+++ b/internal/topic/topicreaderinternal/message_content_pool_test.go
@@ -48,6 +48,7 @@ func TestCallbackOnReaderContent(t *testing.T) {
err := callbackOnReaderContent(p, newReader(), 0, testFuncConsumer(func(data []byte) error {
called = true
require.Equal(t, expectedData, data)
+
return nil
}))
require.NoError(t, err)
@@ -76,6 +77,7 @@ func TestCallbackOnReaderContent(t *testing.T) {
// first call with empty reader - for check internal capacity without reallocation
_ = callbackOnReaderContent(p, ErrReader(io.EOF), estimatedSize, testFuncConsumer(func(data []byte) error {
require.Empty(t, data)
+
return nil
}))
@@ -84,6 +86,7 @@ func TestCallbackOnReaderContent(t *testing.T) {
err := callbackOnReaderContent(p, newReader(), estimatedSize, testFuncConsumer(func(data []byte) error {
require.Equal(t, expectedData, data)
called = true
+
return nil
}))
require.NoError(t, err)
@@ -103,6 +106,7 @@ func TestCallbackOnReaderContent(t *testing.T) {
err := callbackOnReaderContent(p, newReader(), maxInitialBufferSize+10, testFuncConsumer(func(data []byte) error {
require.Equal(t, expectedData, data)
called = true
+
return nil
}))
require.NoError(t, err)
@@ -121,6 +125,7 @@ func TestCallbackOnReaderContent(t *testing.T) {
err := callbackOnReaderContent(p, newReader(), 0, testFuncConsumer(func(data []byte) error {
require.Equal(t, expectedData, data)
called = true
+
return nil
}))
require.NoError(t, err)
diff --git a/internal/topic/topicreaderinternal/partition_session.go b/internal/topic/topicreaderinternal/partition_session.go
index 9eca843bb..9e23c5495 100644
--- a/internal/topic/topicreaderinternal/partition_session.go
+++ b/internal/topic/topicreaderinternal/partition_session.go
@@ -4,10 +4,10 @@ import (
"context"
"fmt"
"sync"
+ "sync/atomic"
"time"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicreader"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
@@ -28,8 +28,8 @@ type partitionSession struct {
ctxCancel context.CancelFunc
partitionSessionID rawtopicreader.PartitionSessionID
- lastReceivedOffsetEndVal xatomic.Int64
- committedOffsetVal xatomic.Int64
+ lastReceivedOffsetEndVal atomic.Int64
+ committedOffsetVal atomic.Int64
}
func newPartitionSession(
@@ -54,6 +54,7 @@ func newPartitionSession(
}
res.committedOffsetVal.Store(committedOffset.ToInt64())
res.lastReceivedOffsetEndVal.Store(committedOffset.ToInt64() - 1)
+
return res
}
@@ -70,6 +71,7 @@ func (s *partitionSession) committedOffset() rawtopicreader.Offset {
var res rawtopicreader.Offset
res.FromInt64(v)
+
return res
}
@@ -82,6 +84,7 @@ func (s *partitionSession) lastReceivedMessageOffset() rawtopicreader.Offset {
var res rawtopicreader.Offset
res.FromInt64(v)
+
return res
}
@@ -112,6 +115,7 @@ func (c *partitionSessionStorage) Add(session *partitionSession) error {
return xerrors.WithStackTrace(fmt.Errorf("session id already existed: %v", session.partitionSessionID))
}
c.sessions[session.partitionSessionID] = &sessionInfo{Session: session}
+
return nil
}
@@ -135,6 +139,7 @@ func (c *partitionSessionStorage) Remove(id partitionSessionID) (*partitionSessi
c.removeIndex++
if partitionInfo, ok := c.sessions[id]; ok {
partitionInfo.RemoveTime = now
+
return partitionInfo.Session, nil
}
diff --git a/internal/topic/topicreaderinternal/reader.go b/internal/topic/topicreaderinternal/reader.go
index 31144d6fc..b499221d1 100644
--- a/internal/topic/topicreaderinternal/reader.go
+++ b/internal/topic/topicreaderinternal/reader.go
@@ -73,6 +73,7 @@ type readExplicitMessagesCount int
func (count readExplicitMessagesCount) Apply(options ReadMessageBatchOptions) ReadMessageBatchOptions {
options.MinCount = int(count)
options.MaxCount = int(count)
+
return options
}
@@ -257,9 +258,9 @@ func convertNewParamsToStreamConfig(
cfg.ReadSelectors[i] = readSelectors[i].Clone()
}
- for _, f := range opts {
- if f != nil {
- f(&cfg)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&cfg)
}
}
@@ -276,5 +277,6 @@ type PublicReadSelector struct {
// Clone create deep clone of the selector
func (s PublicReadSelector) Clone() *PublicReadSelector { //nolint:gocritic
s.Partitions = clone.Int64Slice(s.Partitions)
+
return &s
}
diff --git a/internal/topic/topicreaderinternal/reader_test.go b/internal/topic/topicreaderinternal/reader_test.go
index 56f7e1de9..4b73a9559 100644
--- a/internal/topic/topicreaderinternal/reader_test.go
+++ b/internal/topic/topicreaderinternal/reader_test.go
@@ -62,6 +62,7 @@ func TestReader_Close(t *testing.T) {
callCompleted: make(empty.Chan),
}
allStates = append(allStates, state)
+
return state
}
diff --git a/internal/topic/topicreaderinternal/stream_reader_impl.go b/internal/topic/topicreaderinternal/stream_reader_impl.go
index b85899040..381ccd690 100644
--- a/internal/topic/topicreaderinternal/stream_reader_impl.go
+++ b/internal/topic/topicreaderinternal/stream_reader_impl.go
@@ -9,13 +9,13 @@ import (
"math/big"
"reflect"
"runtime/pprof"
+ "sync/atomic"
"time"
"github.com/ydb-platform/ydb-go-sdk/v3/credentials"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/background"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopiccommon"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicreader"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
@@ -25,8 +25,7 @@ import (
var (
PublicErrCommitSessionToExpiredSession = xerrors.Wrap(errors.New("ydb: commit to expired session"))
- errPartitionSessionStoppedByServer = xerrors.Wrap(errors.New("ydb: topic partition session stopped by server"))
- errCommitWithNilPartitionSession = xerrors.Wrap(errors.New("ydb: commit with nil partition session"))
+ errCommitWithNilPartitionSession = xerrors.Wrap(errors.New("ydb: commit with nil partition session"))
)
type partitionSessionID = rawtopicreader.PartitionSessionID
@@ -37,7 +36,7 @@ type topicStreamReaderImpl struct {
cancel context.CancelFunc
freeBytes chan int
- restBufferSizeBytes xatomic.Int64
+ restBufferSizeBytes atomic.Int64
sessionController partitionSessionStorage
backgroundWorkers background.Worker
@@ -160,6 +159,7 @@ func newTopicStreamReaderStopped(
res.committer.BufferCountTrigger = cfg.CommitterBatchCounterTrigger
res.sessionController.init()
res.freeBytes <- cfg.BufferSizeProtoBytes
+
return res
}
@@ -167,6 +167,7 @@ func (r *topicStreamReaderImpl) WaitInit(_ context.Context) error {
if !r.started {
return errors.New("not started: can be started only after initialize from constructor")
}
+
return nil
}
@@ -263,6 +264,7 @@ func (r *topicStreamReaderImpl) consumeRawMessageFromBuffer(ctx context.Context)
case *rawtopicreader.StartPartitionSessionRequest:
if err := r.onStartPartitionSessionRequestFromBuffer(m); err != nil {
_ = r.CloseWithError(ctx, err)
+
return
}
case *rawtopicreader.StopPartitionSessionRequest:
@@ -270,6 +272,7 @@ func (r *topicStreamReaderImpl) consumeRawMessageFromBuffer(ctx context.Context)
_ = r.CloseWithError(ctx, xerrors.WithStackTrace(
fmt.Errorf("ydb: unexpected error on stop partition handler: %w", err),
))
+
return
}
case *rawtopicreader.PartitionSessionStatusResponse:
@@ -366,6 +369,7 @@ func (r *topicStreamReaderImpl) Commit(ctx context.Context, commitRange commitRa
if err = r.checkCommitRange(commitRange); err != nil {
return err
}
+
return r.committer.Commit(ctx, commitRange)
}
@@ -380,7 +384,7 @@ func (r *topicStreamReaderImpl) checkCommitRange(commitRange commitRange) error
}
if session.Context().Err() != nil {
- return xerrors.WithStackTrace(fmt.Errorf("ydb: commit error: %w", errPartitionSessionStoppedByServer))
+ return xerrors.WithStackTrace(PublicErrCommitSessionToExpiredSession)
}
ownSession, err := r.sessionController.Get(session.partitionSessionID)
@@ -400,6 +404,7 @@ func (r *topicStreamReaderImpl) send(msg rawtopicreader.ClientMessage) error {
trace.TopicOnReaderError(r.cfg.Trace, r.readConnectionID, err)
_ = r.CloseWithError(r.ctx, err)
}
+
return err
}
@@ -426,6 +431,7 @@ func (r *topicStreamReaderImpl) setStarted() error {
}
r.started = true
+
return nil
}
@@ -465,6 +471,7 @@ func (r *topicStreamReaderImpl) addRestBufferBytes(delta int) int {
if val <= 0 {
r.batcher.IgnoreMinRestrictionsOnNextPop()
}
+
return int(val)
}
@@ -487,6 +494,7 @@ func (r *topicStreamReaderImpl) readMessagesLoop(ctx context.Context) {
continue
}
_ = r.CloseWithError(ctx, err)
+
return
}
@@ -507,16 +515,19 @@ func (r *topicStreamReaderImpl) readMessagesLoop(ctx context.Context) {
case *rawtopicreader.StartPartitionSessionRequest:
if err = r.onStartPartitionSessionRequest(m); err != nil {
_ = r.CloseWithError(ctx, err)
+
return
}
case *rawtopicreader.StopPartitionSessionRequest:
if err = r.onStopPartitionSessionRequest(m); err != nil {
_ = r.CloseWithError(ctx, err)
+
return
}
case *rawtopicreader.CommitOffsetResponse:
if err = r.onCommitResponse(m); err != nil {
_ = r.CloseWithError(ctx, err)
+
return
}
@@ -546,6 +557,7 @@ func (r *topicStreamReaderImpl) dataRequestLoop(ctx context.Context) {
select {
case <-doneChan:
_ = r.CloseWithError(ctx, r.ctx.Err())
+
return
case free := <-r.freeBytes:
@@ -686,6 +698,7 @@ func (r *topicStreamReaderImpl) CloseWithError(ctx context.Context, reason error
if closeErr == nil {
closeErr = bgCloseErr
}
+
return closeErr
}
@@ -741,6 +754,7 @@ func (r *topicStreamReaderImpl) onStartPartitionSessionRequest(m *rawtopicreader
if err := r.sessionController.Add(session); err != nil {
return err
}
+
return r.batcher.PushRawMessage(session, m)
}
diff --git a/internal/topic/topicreaderinternal/stream_reader_impl_test.go b/internal/topic/topicreaderinternal/stream_reader_impl_test.go
index 4cf05a21c..a518c2058 100644
--- a/internal/topic/topicreaderinternal/stream_reader_impl_test.go
+++ b/internal/topic/topicreaderinternal/stream_reader_impl_test.go
@@ -391,6 +391,7 @@ func TestStreamReaderImpl_OnPartitionCloseHandle(t *testing.T) {
require.NoError(t, info.PartitionContext.Err())
readMessagesCtxCancel()
+
return nil
}
@@ -434,6 +435,7 @@ func TestStreamReaderImpl_OnPartitionCloseHandle(t *testing.T) {
require.Error(t, info.PartitionContext.Err())
readMessagesCtxCancel()
+
return nil
}
@@ -577,6 +579,7 @@ func TestTopicStreamReaderImpl_ReadMessages(t *testing.T) {
_, err := writer.Write([]byte(msg))
require.NoError(t, writer.Close())
require.NoError(t, err)
+
return b.Bytes()
}
@@ -842,6 +845,7 @@ func TestTopicStreamReadImpl_BatchReaderWantMoreMessagesThenBufferCanHold(t *tes
},
},
})
+
return nextDataRequested
}
@@ -935,6 +939,7 @@ func TestTopicStreamReadImpl_CommitWithBadSession(t *testing.T) {
sleep()
require.False(t, e.reader.closed)
+
return commitErr
}
t.Run("CommitModeNone", func(t *testing.T) {
@@ -1109,6 +1114,7 @@ readMessages:
e.m.WithLock(func() {
e.nextMessageNeedCallback = res.nextMessageCallback
})
+
return res.msg, res.err
}
}
diff --git a/internal/topic/topicreaderinternal/stream_reconnector.go b/internal/topic/topicreaderinternal/stream_reconnector.go
index 6bae747f0..393b0ecea 100644
--- a/internal/topic/topicreaderinternal/stream_reconnector.go
+++ b/internal/topic/topicreaderinternal/stream_reconnector.go
@@ -29,30 +29,24 @@ var (
type readerConnectFunc func(ctx context.Context) (batchedStreamReader, error)
type readerReconnector struct {
- clock clockwork.Clock
- background background.Worker
-
- tracer *trace.Topic
- baseContext context.Context
- retrySettings topic.RetrySettings
-
- readerConnect readerConnectFunc
-
- reconnectFromBadStream chan reconnectRequest
- connectTimeout time.Duration
-
- closeOnce sync.Once
- readerID int64
-
- m xsync.RWMutex
- streamConnectionInProgress empty.Chan // opened if connection in progress, closed if connection established
+ background background.Worker
+ clock clockwork.Clock
+ baseContext context.Context
+ retrySettings topic.RetrySettings
streamVal batchedStreamReader
streamErr error
closedErr error
-
- initErr error
- initDone bool
- initDoneCh empty.Chan
+ initErr error
+ tracer *trace.Topic
+ readerConnect readerConnectFunc
+ reconnectFromBadStream chan reconnectRequest
+ connectTimeout time.Duration
+ readerID int64
+ streamConnectionInProgress empty.Chan // opened if connection in progress, closed if connection established
+ initDoneCh empty.Chan
+ m xsync.RWMutex
+ closeOnce sync.Once
+ initDone bool
}
//nolint:revive
@@ -115,6 +109,7 @@ func (r *readerReconnector) ReadMessageBatch(ctx context.Context, opts ReadMessa
case r.isRetriableError(err):
r.fireReconnectOnRetryableError(stream, err)
runtime.Gosched()
+
continue
case err != nil:
return nil, err
@@ -126,8 +121,10 @@ func (r *readerReconnector) ReadMessageBatch(ctx context.Context, opts ReadMessa
if r.isRetriableError(err) {
r.fireReconnectOnRetryableError(stream, err)
runtime.Gosched()
+
continue
}
+
return res, err
}
}
@@ -140,6 +137,7 @@ func (r *readerReconnector) Commit(ctx context.Context, commitRange commitRange)
err = stream.Commit(ctx, commitRange)
r.fireReconnectOnRetryableError(stream, err)
+
return err
}
@@ -166,6 +164,7 @@ func (r *readerReconnector) CloseWithError(ctx context.Context, err error) error
}
})
})
+
return closeErr
}
@@ -292,11 +291,13 @@ func (r *readerReconnector) reconnect(ctx context.Context, reason error, oldRead
}
}
})
+
return err
}
func (r *readerReconnector) isRetriableError(err error) bool {
_, res := topic.CheckRetryMode(err, r.retrySettings, 0)
+
return res
}
@@ -341,6 +342,7 @@ func (r *readerReconnector) connectWithTimeout() (_ batchedStreamReader, err err
if res.err == nil {
return res.stream, nil
}
+
return nil, res.err
}
@@ -383,6 +385,7 @@ func (r *readerReconnector) stream(ctx context.Context) (batchedStreamReader, er
connectionChan = r.streamConnectionInProgress
if r.closedErr != nil {
err = r.closedErr
+
return
}
})
@@ -402,6 +405,7 @@ func (r *readerReconnector) stream(ctx context.Context) (batchedStreamReader, er
err = r.streamErr
})
r.fireReconnectOnRetryableError(reader, err)
+
return reader, err
}
}
diff --git a/internal/topic/topicreaderinternal/stream_reconnector_test.go b/internal/topic/topicreaderinternal/stream_reconnector_test.go
index 57b0f00dc..d9034066e 100644
--- a/internal/topic/topicreaderinternal/stream_reconnector_test.go
+++ b/internal/topic/topicreaderinternal/stream_reconnector_test.go
@@ -61,6 +61,7 @@ func TestTopicReaderReconnectorReadMessageBatch(t *testing.T) {
if connectCalled > 1 {
return nil, errors.New("unexpected call test connect function")
}
+
return baseReader, nil
},
streamErr: errUnconnected,
@@ -103,6 +104,7 @@ func TestTopicReaderReconnectorReadMessageBatch(t *testing.T) {
reader := &readerReconnector{
readerConnect: func(ctx context.Context) (batchedStreamReader, error) {
connectCalled++
+
return readers[connectCalled-1], nil
},
streamErr: errUnconnected,
@@ -218,6 +220,7 @@ func TestTopicReaderReconnectorConnectionLoop(t *testing.T) {
{
callback: func(ctx context.Context) (batchedStreamReader, error) {
close(stream1Ready)
+
return newStream1, nil
},
},
@@ -227,12 +230,14 @@ func TestTopicReaderReconnectorConnectionLoop(t *testing.T) {
{
callback: func(ctx context.Context) (batchedStreamReader, error) {
close(stream2Ready)
+
return newStream2, nil
},
},
{
callback: func(ctx context.Context) (batchedStreamReader, error) {
t.Fatal()
+
return nil, errors.New("unexpected call")
},
},
@@ -288,10 +293,12 @@ func TestTopicReaderReconnectorStart(t *testing.T) {
reconnector.readerConnect = readerConnectFuncMock([]readerConnectFuncAnswer{
{callback: func(ctx context.Context) (batchedStreamReader, error) {
close(connectionRequested)
+
return stream, nil
}},
{callback: func(ctx context.Context) (batchedStreamReader, error) {
t.Error()
+
return nil, errors.New("unexpected call")
}},
}...)
@@ -345,6 +352,7 @@ func TestTopicReaderReconnectorWaitInit(t *testing.T) {
reconnector.readerConnect = readerConnectFuncMock(readerConnectFuncAnswer{
callback: func(ctx context.Context) (batchedStreamReader, error) {
cancel()
+
return stream, nil
},
})
diff --git a/internal/topic/topicwriterinternal/encoders.go b/internal/topic/topicwriterinternal/encoders.go
index 60eb3e2dc..7ae89d534 100644
--- a/internal/topic/topicwriterinternal/encoders.go
+++ b/internal/topic/topicwriterinternal/encoders.go
@@ -42,6 +42,7 @@ func (e *EncoderMap) CreateLazyEncodeWriter(codec rawtopiccommon.Codec, target i
if encoderCreator, ok := e.m[codec]; ok {
return encoderCreator(target)
}
+
return nil, xerrors.WithStackTrace(xerrors.Wrap(fmt.Errorf("ydb: unexpected codec '%v' for encode message", codec)))
}
@@ -50,11 +51,13 @@ func (e *EncoderMap) GetSupportedCodecs() rawtopiccommon.SupportedCodecs {
for codec := range e.m {
res = append(res, codec)
}
+
return res
}
func (e *EncoderMap) IsSupported(codec rawtopiccommon.Codec) bool {
_, ok := e.m[codec]
+
return ok
}
@@ -122,6 +125,7 @@ func (s *EncoderSelector) CompressMessages(messages []messageWithDataContent) (r
err = cacheMessages(messages, codec, s.parallelCompressors)
onCompressDone(err)
}
+
return codec, err
}
@@ -257,6 +261,7 @@ func cacheMessages(messages []messageWithDataContent, codec rawtopiccommon.Codec
resErrMutex.WithLock(func() {
resErr = localErr
})
+
return
}
}
diff --git a/internal/topic/topicwriterinternal/message.go b/internal/topic/topicwriterinternal/message.go
index 9b1088b95..5c618e631 100644
--- a/internal/topic/topicwriterinternal/message.go
+++ b/internal/topic/topicwriterinternal/message.go
@@ -9,7 +9,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopiccommon"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicwriter"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xbytes"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
@@ -38,6 +37,7 @@ func (p PublicFuturePartitioning) ToRaw() rawtopicwriter.Partitioning {
if p.hasPartitionID {
return rawtopicwriter.NewPartitioningPartitionID(p.partitionID)
}
+
return rawtopicwriter.NewPartitioningMessageGroup(p.messageGroupID)
}
@@ -58,14 +58,14 @@ type messageWithDataContent struct {
PublicMessage
dataWasRead bool
- encoders *EncoderMap
hasRawContent bool
- rawBuf bytes.Buffer
hasEncodedContent bool
+ metadataCached bool
bufCodec rawtopiccommon.Codec
bufEncoded bytes.Buffer
+ rawBuf bytes.Buffer
+ encoders *EncoderMap
BufUncompressedSize int
- metadataCached bool
}
func (m *messageWithDataContent) GetEncodedBytes(codec rawtopiccommon.Codec) ([]byte, error) {
@@ -85,7 +85,7 @@ func (m *messageWithDataContent) cacheMetadata() {
if len(m.Metadata) > 0 {
ownCopy := make(map[string][]byte, len(m.Metadata))
for key, val := range m.Metadata {
- ownCopy[key] = xbytes.Clone(val)
+ ownCopy[key] = bytes.Clone(val)
}
m.Metadata = ownCopy
} else {
@@ -97,6 +97,7 @@ func (m *messageWithDataContent) cacheMetadata() {
func (m *messageWithDataContent) CacheMessageData(codec rawtopiccommon.Codec) error {
m.cacheMetadata()
_, err := m.GetEncodedBytes(codec)
+
return err
}
@@ -128,6 +129,7 @@ func (m *messageWithDataContent) encodeRawContent(codec rawtopiccommon.Codec) ([
}
m.bufCodec = codec
+
return m.bufEncoded.Bytes(), nil
}
@@ -142,6 +144,7 @@ func (m *messageWithDataContent) readDataToRawBuf() error {
m.BufUncompressedSize = int(writtenBytes)
m.Data = nil
}
+
return nil
}
@@ -173,6 +176,7 @@ func (m *messageWithDataContent) readDataToTargetCodec(codec rawtopiccommon.Code
}
m.BufUncompressedSize = int(bytesCount)
m.Data = nil
+
return nil
}
@@ -188,6 +192,7 @@ func (m *messageWithDataContent) getRawBytes() ([]byte, error) {
if err != nil {
return nil, err
}
+
return m.rawBuf.Bytes(), nil
}
@@ -204,6 +209,7 @@ func (m *messageWithDataContent) getEncodedBytes(codec rawtopiccommon.Codec) ([]
if err != nil {
return nil, err
}
+
return m.bufEncoded.Bytes(), nil
}
}
diff --git a/internal/topic/topicwriterinternal/queue.go b/internal/topic/topicwriterinternal/queue.go
index ab5ff7e56..25ff072d3 100644
--- a/internal/topic/topicwriterinternal/queue.go
+++ b/internal/topic/topicwriterinternal/queue.go
@@ -14,6 +14,7 @@ import (
var (
errCloseClosedMessageQueue = xerrors.Wrap(errors.New("ydb: close closed message queue"))
+ errAckOnClosedMessageQueue = xerrors.Wrap(errors.New("ydb: ack on closed message queue"))
errGetMessageFromClosedQueue = xerrors.Wrap(errors.New("ydb: get message from closed message queue"))
errAddUnorderedMessages = xerrors.Wrap(errors.New("ydb: add unordered messages"))
errAckUnexpectedMessage = xerrors.Wrap(errors.New("ydb: ack unexpected message"))
@@ -57,6 +58,7 @@ func newMessageQueue() messageQueue {
func (q *messageQueue) AddMessages(messages []messageWithDataContent) error {
_, err := q.addMessages(messages, false)
+
return err
}
@@ -136,6 +138,7 @@ func (q *messageQueue) addMessageNeedLock(
q.messagesByOrder[messageIndex] = mess
q.seqNoToOrderID[mess.SeqNo] = messageIndex
q.lastSeqNo = mess.SeqNo
+
return messageIndex
}
@@ -149,6 +152,9 @@ func (q *messageQueue) AcksReceived(acks []rawtopicwriter.WriteAck) error {
q.OnAckReceived(ackReceivedCounter)
}
}()
+ if q.closed {
+ return xerrors.WithStackTrace(errAckOnClosedMessageQueue)
+ }
for i := range acks {
if err := q.ackReceivedNeedLock(acks[i].SeqNo); err != nil {
@@ -158,6 +164,7 @@ func (q *messageQueue) AcksReceived(acks []rawtopicwriter.WriteAck) error {
}
q.acksReceivedEvent.Broadcast()
+
return nil
}
@@ -169,6 +176,7 @@ func (q *messageQueue) ackReceivedNeedLock(seqNo int64) error {
delete(q.seqNoToOrderID, seqNo)
delete(q.messagesByOrder, orderID)
+
return nil
}
@@ -270,6 +278,7 @@ func (q *messageQueue) getMessagesForSendWithLock() []messageWithDataContent {
res = append(res, msg)
}
}
+
return res
}
@@ -288,6 +297,7 @@ func (q *messageQueue) Wait(ctx context.Context, waiter MessageQueueAckWaiter) e
checkMessageIndex := waiter.sequenseNumbers[0]
if _, ok := q.messagesByOrder[checkMessageIndex]; ok {
hasWaited = true
+
return
}
waiter.sequenseNumbers = waiter.sequenseNumbers[1:]
diff --git a/internal/topic/topicwriterinternal/queue_test.go b/internal/topic/topicwriterinternal/queue_test.go
index af2c26033..d62e6b16e 100644
--- a/internal/topic/topicwriterinternal/queue_test.go
+++ b/internal/topic/topicwriterinternal/queue_test.go
@@ -14,7 +14,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicwriter"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
)
@@ -142,7 +141,7 @@ func TestMessageQueue_GetMessages(t *testing.T) {
}()
readFinished := make(empty.Chan)
- var lastReadSeqNo xatomic.Int64
+ var lastReadSeqNo atomic.Int64
readCtx, readCancel := xcontext.WithCancel(ctx)
defer readCancel()
@@ -159,6 +158,7 @@ func TestMessageQueue_GetMessages(t *testing.T) {
for _, mess := range messages {
if lastReadSeqNo.Load()+1 != mess.SeqNo {
fatalChan <- string(debug.Stack())
+
return
}
lastReadSeqNo.Store(mess.SeqNo)
@@ -407,6 +407,26 @@ func TestQueuePanicOnOverflow(t *testing.T) {
})
}
+func TestRegressionIssue1038_ReceiveAckAfterCloseQueue(t *testing.T) {
+ counter := 0
+
+ q := newMessageQueue()
+ q.OnAckReceived = func(count int) {
+ counter -= count
+ }
+ require.NoError(t, q.AddMessages(newTestMessagesWithContent(1)))
+ counter++
+
+ require.NoError(t, q.Close(errors.New("test err")))
+ require.ErrorIs(t, q.AcksReceived([]rawtopicwriter.WriteAck{
+ {
+ SeqNo: 1,
+ MessageWriteStatus: rawtopicwriter.MessageWriteStatus{},
+ },
+ }), errAckOnClosedMessageQueue)
+ require.Zero(t, counter)
+}
+
func TestQueue_Ack(t *testing.T) {
t.Run("First", func(t *testing.T) {
q := newMessageQueue()
@@ -491,5 +511,6 @@ func getSeqNumbers(messages []messageWithDataContent) []int64 {
for i := range messages {
res = append(res, messages[i].SeqNo)
}
+
return res
}
diff --git a/internal/topic/topicwriterinternal/writer_grpc_mock_test.go b/internal/topic/topicwriterinternal/writer_grpc_mock_test.go
new file mode 100644
index 000000000..1a977cb75
--- /dev/null
+++ b/internal/topic/topicwriterinternal/writer_grpc_mock_test.go
@@ -0,0 +1,134 @@
+package topicwriterinternal_test
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/rekby/fixenv"
+ "github.com/rekby/fixenv/sf"
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Topic_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Issue"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Topic"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
+ "github.com/ydb-platform/ydb-go-sdk/v3/topic/topicwriter"
+)
+
+func TestRegressionOperationUnavailableIssue1007(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ e := fixenv.New(t)
+
+ mock := newTopicWriterOperationUnavailable()
+ connString := xtest.GrpcMockTopicConnString(e, mock)
+
+ db, err := ydb.Open(sf.Context(e), connString)
+ require.NoError(t, err)
+
+ writer, err := db.Topic().StartWriter("test", topicoptions.WithWriterWaitServerAck(true))
+ require.NoError(t, err)
+
+ err = writer.Write(sf.Context(e), topicwriter.Message{
+ Data: strings.NewReader("asd"),
+ })
+ require.NoError(t, err)
+ require.True(t, mock.UnavailableResponsed)
+ })
+}
+
+type topicWriterOperationUnavailable struct {
+ Ydb_Topic_V1.UnimplementedTopicServiceServer
+
+ UnavailableResponsed bool
+}
+
+func newTopicWriterOperationUnavailable() *topicWriterOperationUnavailable {
+ return &topicWriterOperationUnavailable{}
+}
+
+func (t *topicWriterOperationUnavailable) StreamWrite(server Ydb_Topic_V1.TopicService_StreamWriteServer) error {
+ initMsg, err := server.Recv()
+ if err != nil {
+ return fmt.Errorf("failed read init message: %w", err)
+ }
+
+ if initMsg.GetInitRequest() == nil {
+ return errors.New("first message must be init message")
+ }
+
+ err = server.Send(&Ydb_Topic.StreamWriteMessage_FromServer{
+ Status: Ydb.StatusIds_SUCCESS,
+ ServerMessage: &Ydb_Topic.StreamWriteMessage_FromServer_InitResponse{
+ InitResponse: &Ydb_Topic.StreamWriteMessage_InitResponse{
+ LastSeqNo: 0,
+ SessionId: "test",
+ PartitionId: 0,
+ SupportedCodecs: nil,
+ },
+ },
+ })
+ if err != nil {
+ return fmt.Errorf("failed to send init response: %w", err)
+ }
+
+ if !t.UnavailableResponsed {
+ t.UnavailableResponsed = true
+
+ err = server.Send(&Ydb_Topic.StreamWriteMessage_FromServer{
+ Status: Ydb.StatusIds_UNAVAILABLE,
+ Issues: []*Ydb_Issue.IssueMessage{
+ {
+ Message: "Test status unavailable",
+ },
+ },
+ })
+
+ if err != nil {
+ return fmt.Errorf("failed to send error response: %w", err)
+ }
+
+ return nil
+ }
+
+ // wait message block
+ messagesMsg, err := server.Recv()
+ if err != nil {
+ return errors.New("failed to read messages block")
+ }
+
+ if len(messagesMsg.GetClientMessage().(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest).
+ WriteRequest.GetMessages()) == 0 {
+ return errors.New("received zero messages block")
+ }
+
+ err = server.Send(&Ydb_Topic.StreamWriteMessage_FromServer{
+ Status: Ydb.StatusIds_SUCCESS,
+ ServerMessage: &Ydb_Topic.StreamWriteMessage_FromServer_WriteResponse{
+ WriteResponse: &Ydb_Topic.StreamWriteMessage_WriteResponse{
+ Acks: []*Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck{
+ {
+ SeqNo: 1,
+ MessageWriteStatus: &Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Written_{
+ Written: &Ydb_Topic.StreamWriteMessage_WriteResponse_WriteAck_Written{
+ Offset: 1,
+ },
+ },
+ },
+ },
+ PartitionId: 0,
+ WriteStatistics: &Ydb_Topic.StreamWriteMessage_WriteResponse_WriteStatistics{},
+ },
+ },
+ })
+
+ if err != nil {
+ return fmt.Errorf("failed to sent write ack: %w", err)
+ }
+
+ return nil
+}
diff --git a/internal/topic/topicwriterinternal/writer_reconnector.go b/internal/topic/topicwriterinternal/writer_reconnector.go
index fcd1eabf7..dd7c1b72d 100644
--- a/internal/topic/topicwriterinternal/writer_reconnector.go
+++ b/internal/topic/topicwriterinternal/writer_reconnector.go
@@ -8,6 +8,7 @@ import (
"math"
"math/big"
"runtime"
+ "sync/atomic"
"time"
"github.com/google/uuid"
@@ -22,7 +23,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicwriter"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/topic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
@@ -69,6 +69,7 @@ func (cfg *WriterReconnectorConfig) validate() error {
cfg.producerID != cfg.defaultPartitioning.MessageGroupID {
return xerrors.WithStackTrace(errProducerIDNotEqualMessageGroupID)
}
+
return nil
}
@@ -113,25 +114,22 @@ func newWriterReconnectorConfig(options ...PublicWriterOption) WriterReconnector
}
type WriterReconnector struct {
- cfg WriterReconnectorConfig
- retrySettings topic.RetrySettings
-
- semaphore *semaphore.Weighted
+ cfg WriterReconnectorConfig
queue messageQueue
background background.Worker
+ retrySettings topic.RetrySettings
clock clockwork.Clock
- firstConnectionHandled xatomic.Bool
- firstInitResponseProcessedChan empty.Chan
writerInstanceID string
-
- m xsync.RWMutex
- sessionID string
- lastSeqNo int64
- encodersMap *EncoderMap
-
- initDone bool
- initDoneCh empty.Chan
- initInfo InitialInfo
+ sessionID string
+ semaphore *semaphore.Weighted
+ firstInitResponseProcessedChan empty.Chan
+ lastSeqNo int64
+ encodersMap *EncoderMap
+ initDoneCh empty.Chan
+ initInfo InitialInfo
+ m xsync.RWMutex
+ firstConnectionHandled atomic.Bool
+ initDone bool
}
func newWriterReconnector(
@@ -139,6 +137,7 @@ func newWriterReconnector(
) *WriterReconnector {
res := newWriterReconnectorStopped(cfg)
res.start()
+
return res
}
@@ -288,6 +287,7 @@ func (w *WriterReconnector) checkMessages(messages []messageWithDataContent) err
return xerrors.WithStackTrace(fmt.Errorf("message size bytes %v: %w", size, errLargeMessage))
}
}
+
return nil
}
@@ -321,6 +321,7 @@ func (w *WriterReconnector) createMessagesWithContent(messages []PublicMessage)
if err != nil {
return nil, err
}
+
return res, nil
}
@@ -339,6 +340,7 @@ func (w *WriterReconnector) close(ctx context.Context, reason error) (resErr err
if resErr == nil {
resErr = bgErr
}
+
return resErr
}
@@ -348,7 +350,7 @@ func (w *WriterReconnector) connectionLoop(ctx context.Context) {
createStreamContext := func() (context.Context, context.CancelFunc) {
// need suppress parent context cancelation for flush buffer while close writer
- return xcontext.WithCancel(xcontext.WithoutDeadline(ctx))
+ return xcontext.WithCancel(xcontext.ValueOnly(ctx))
}
//nolint:ineffassign,staticcheck,wastedassign
@@ -369,7 +371,7 @@ func (w *WriterReconnector) connectionLoop(ctx context.Context) {
streamCtx, streamCtxCancel = createStreamContext()
now := time.Now()
- if topic.CheckResetReconnectionCounters(prevAttemptTime, now, w.cfg.connectTimeout) {
+ if startOfRetries.IsZero() || topic.CheckResetReconnectionCounters(prevAttemptTime, now, w.cfg.connectTimeout) {
attempt = 0
startOfRetries = w.clock.Now()
} else {
@@ -388,6 +390,7 @@ func (w *WriterReconnector) connectionLoop(ctx context.Context) {
}
} else {
_ = w.close(ctx, reconnectReason)
+
return
}
}
@@ -424,11 +427,13 @@ func (w *WriterReconnector) startWriteStream(ctx, streamCtx context.Context, att
}
w.queue.ResetSentProgress()
+
return NewSingleStreamWriter(ctx, w.createWriterStreamConfig(stream))
}
func (w *WriterReconnector) needReceiveLastSeqNo() bool {
- res := w.cfg.AutoSetSeqNo && !w.firstConnectionHandled.Load()
+ res := !w.firstConnectionHandled.Load()
+
return res
}
@@ -462,11 +467,13 @@ func (w *WriterReconnector) connectWithTimeout(streamLifetimeContext context.Con
select {
case <-timer.C:
connectCancel()
+
return nil, xerrors.WithStackTrace(errConnTimeout)
case res := <-resCh:
// force no cancel connect context - because it will break stream
// context will cancel by cancel streamLifetimeContext while reconnect or stop connection
_ = connectCancel
+
return res.stream, res.err
}
}
@@ -480,6 +487,7 @@ func (w *WriterReconnector) onWriterChange(writerStream *SingleStreamWriter) {
w.m.WithLock(func() {
if writerStream == nil {
w.sessionID = ""
+
return
}
w.sessionID = writerStream.SessionID
@@ -490,7 +498,7 @@ func (w *WriterReconnector) onWriterChange(writerStream *SingleStreamWriter) {
defer close(w.firstInitResponseProcessedChan)
isFirstInit = true
- if w.cfg.AutoSetSeqNo {
+ if writerStream.LastSeqNumRequested {
w.lastSeqNo = writerStream.ReceivedLastSeqNum
}
})
@@ -561,6 +569,7 @@ func (w *WriterReconnector) createWriterStreamConfig(stream RawTopicWriterStream
w.needReceiveLastSeqNo(),
w.writerInstanceID,
)
+
return cfg
}
@@ -581,6 +590,7 @@ func sendMessagesToStream(
if err != nil {
return xerrors.WithStackTrace(fmt.Errorf("ydb: failed send write request: %w", err))
}
+
return nil
}
@@ -614,6 +624,7 @@ func splitMessagesByBufCodec(messages []messageWithDataContent) (res [][]message
}
}
res = append(res, messages[currentGroupStart:len(messages):len(messages)])
+
return res
}
@@ -674,6 +685,7 @@ func calculateAllowedCodecs(forceCodec rawtopiccommon.Codec, encoderMap *Encoder
if serverCodecs.AllowedByCodecsList(forceCodec) && encoderMap.IsSupported(forceCodec) {
return rawtopiccommon.SupportedCodecs{forceCodec}
}
+
return nil
}
@@ -692,6 +704,7 @@ func calculateAllowedCodecs(forceCodec rawtopiccommon.Codec, encoderMap *Encoder
if len(res) == 0 {
res = nil
}
+
return res
}
@@ -702,5 +715,6 @@ func createPublicCodecsFromRaw(codecs rawtopiccommon.SupportedCodecs) []topictyp
for i, v := range codecs {
res[i] = topictypes.Codec(v)
}
+
return res
}
diff --git a/internal/topic/topicwriterinternal/writer_reconnector_test.go b/internal/topic/topicwriterinternal/writer_reconnector_test.go
index 618e61706..4bf18c6ff 100644
--- a/internal/topic/topicwriterinternal/writer_reconnector_test.go
+++ b/internal/topic/topicwriterinternal/writer_reconnector_test.go
@@ -20,7 +20,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopiccommon"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicwriter"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawydb"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
@@ -282,6 +281,7 @@ func TestWriterReconnector_Write_QueueLimit(t *testing.T) {
waitStartQueueWait := func(targetWaiters int) {
xtest.SpinWaitCondition(t, nil, func() bool {
res := getWaitersCount(w.semaphore) == targetWaiters
+
return res
})
}
@@ -328,8 +328,9 @@ func TestWriterImpl_InitSession(t *testing.T) {
sessionID := "test-session-id"
w.onWriterChange(&SingleStreamWriter{
- ReceivedLastSeqNum: lastSeqNo,
- SessionID: sessionID,
+ ReceivedLastSeqNum: lastSeqNo,
+ LastSeqNumRequested: true,
+ SessionID: sessionID,
})
require.Equal(t, sessionID, w.sessionID)
@@ -344,7 +345,8 @@ func TestWriterImpl_WaitInit(t *testing.T) {
LastSeqNum: int64(123),
}
w.onWriterChange(&SingleStreamWriter{
- ReceivedLastSeqNum: expectedInitData.LastSeqNum,
+ ReceivedLastSeqNum: expectedInitData.LastSeqNum,
+ LastSeqNumRequested: true,
})
initData, err := w.WaitInit(context.Background())
@@ -405,6 +407,7 @@ func TestWriterImpl_Reconnect(t *testing.T) {
close(connectCalledChan)
connectCalled = true
require.NotEqual(t, ctx, streamCtxArg)
+
return strm, nil
}
@@ -432,9 +435,15 @@ func TestWriterImpl_Reconnect(t *testing.T) {
connectionError error
}
+ isFirstConnection := true
newStream := func(name string) *MockRawTopicWriterStream {
strm := NewMockRawTopicWriterStream(mc)
initReq := testCreateInitRequest(w)
+ if isFirstConnection {
+ isFirstConnection = false
+ } else {
+ initReq.GetLastSeqNo = false
+ }
streamClosed := make(empty.Chan)
strm.EXPECT().CloseSend().Do(func() {
@@ -458,6 +467,7 @@ func TestWriterImpl_Reconnect(t *testing.T) {
xtest.WaitChannelClosed(t, streamClosed)
t.Logf("channel closed: %v", name)
}).Return(nil, errors.New("test stream closed")).MaxTimes(1)
+
return strm
}
@@ -497,7 +507,7 @@ func TestWriterImpl_Reconnect(t *testing.T) {
},
}
- var connectionAttempt xatomic.Int64
+ var connectionAttempt atomic.Int64
w.cfg.Connect = func(ctx context.Context) (RawTopicWriterStream, error) {
attemptIndex := int(connectionAttempt.Add(1)) - 1
t.Logf("connect with attempt index: %v", attemptIndex)
@@ -516,7 +526,7 @@ func TestWriterImpl_Reconnect(t *testing.T) {
err := w.Write(ctx, newTestMessages(1))
require.NoError(t, err)
- xtest.WaitChannelClosed(t, connectionLoopStopped)
+ xtest.WaitChannelClosedWithTimeout(t, connectionLoopStopped, 4*time.Second)
})
}
@@ -750,6 +760,7 @@ func TestCalculateAllowedCodecs(t *testing.T) {
func newTestMessageWithDataContent(num int) messageWithDataContent {
res := newMessageDataWithContent(PublicMessage{SeqNo: int64(num)}, testCommonEncoders)
+
return res
}
@@ -758,6 +769,7 @@ func newTestMessages(numbers ...int) []PublicMessage {
for i, num := range numbers {
messages[i].SeqNo = int64(num)
}
+
return messages
}
@@ -766,6 +778,7 @@ func newTestMessagesWithContent(numbers ...int) []messageWithDataContent {
for _, num := range numbers {
messages = append(messages, newTestMessageWithDataContent(num))
}
+
return messages
}
@@ -800,6 +813,7 @@ func isClosed(ch <-chan struct{}) bool {
if existVal {
panic("value, when not expected")
}
+
return true
default:
return false
@@ -843,6 +857,7 @@ func newTestEnv(t testing.TB, options *testEnvOptions) *testEnv {
if connectNum > 1 {
t.Fatalf("test: default env support most one connection")
}
+
return res.stream, nil
}))
writerOptions = append(writerOptions, options.writerOptions...)
@@ -880,6 +895,7 @@ func newTestEnv(t testing.TB, options *testEnvOptions) *testEnv {
close(res.stopReadEvents)
<-streamClosed
})
+
return res
}
@@ -907,5 +923,6 @@ type sendFromServerResponse struct {
func testCreateInitRequest(w *WriterReconnector) rawtopicwriter.InitRequest {
req := newSingleStreamWriterStopped(context.Background(), w.createWriterStreamConfig(nil)).createInitRequest()
+
return req
}
diff --git a/internal/topic/topicwriterinternal/writer_reconnector_unsafe_test.go b/internal/topic/topicwriterinternal/writer_reconnector_unsafe_test.go
index 4d0610ff3..0b0d8cd44 100644
--- a/internal/topic/topicwriterinternal/writer_reconnector_unsafe_test.go
+++ b/internal/topic/topicwriterinternal/writer_reconnector_unsafe_test.go
@@ -24,5 +24,6 @@ func getWaitersCount(sem *semaphore.Weighted) int {
waitersField := semVal.FieldByName("waiters")
waitersPointer := unsafe.Pointer(waitersField.UnsafeAddr())
waiters := (*list.List)(waitersPointer)
+
return waiters.Len()
}
diff --git a/internal/topic/topicwriterinternal/writer_single_stream.go b/internal/topic/topicwriterinternal/writer_single_stream.go
index 3d835398d..4f01c56d1 100644
--- a/internal/topic/topicwriterinternal/writer_single_stream.go
+++ b/internal/topic/topicwriterinternal/writer_single_stream.go
@@ -5,12 +5,12 @@ import (
"errors"
"fmt"
"reflect"
+ "sync/atomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/background"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopiccommon"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/grpcwrapper/rawtopic/rawtopicwriter"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
@@ -24,7 +24,7 @@ type SingleStreamWriterConfig struct {
stream RawTopicWriterStream
queue *messageQueue
encodersMap *EncoderMap
- getAutoSeq bool
+ getLastSeqNum bool
reconnectorInstanceID string
}
@@ -33,7 +33,7 @@ func newSingleStreamWriterConfig(
stream RawTopicWriterStream,
queue *messageQueue,
encodersMap *EncoderMap,
- getAutoSeq bool,
+ getLastSeqNum bool,
reconnectorID string,
) SingleStreamWriterConfig {
return SingleStreamWriterConfig{
@@ -41,24 +41,24 @@ func newSingleStreamWriterConfig(
stream: stream,
queue: queue,
encodersMap: encodersMap,
- getAutoSeq: getAutoSeq,
+ getLastSeqNum: getLastSeqNum,
reconnectorInstanceID: reconnectorID,
}
}
type SingleStreamWriter struct {
- ReceivedLastSeqNum int64
- SessionID string
- PartitionID int64
- CodecsFromServer rawtopiccommon.SupportedCodecs
- Encoder EncoderSelector
-
- cfg SingleStreamWriterConfig
- allowedCodecs rawtopiccommon.SupportedCodecs
- background background.Worker
- closed xatomic.Bool
- closeReason error
- closeCompleted empty.Chan
+ cfg SingleStreamWriterConfig
+ Encoder EncoderSelector
+ background background.Worker
+ CodecsFromServer rawtopiccommon.SupportedCodecs
+ allowedCodecs rawtopiccommon.SupportedCodecs
+ SessionID string
+ closeReason error
+ ReceivedLastSeqNum int64
+ PartitionID int64
+ closeCompleted empty.Chan
+ closed atomic.Bool
+ LastSeqNumRequested bool
}
func NewSingleStreamWriter(
@@ -69,9 +69,11 @@ func NewSingleStreamWriter(
err := res.initStream()
if err != nil {
_ = res.close(context.Background(), err)
+
return nil, err
}
res.start()
+
return res, nil
}
@@ -81,7 +83,7 @@ func newSingleStreamWriterStopped(
) *SingleStreamWriter {
return &SingleStreamWriter{
cfg: cfg,
- background: *background.NewWorker(xcontext.WithoutDeadline(ctxForPProfLabelsOnly)),
+ background: *background.NewWorker(xcontext.ValueOnly(ctxForPProfLabelsOnly)),
closeCompleted: make(empty.Chan),
}
}
@@ -152,9 +154,11 @@ func (w *SingleStreamWriter) initStream() (err error) {
)
w.SessionID = result.SessionID
+ w.LastSeqNumRequested = req.GetLastSeqNo
w.ReceivedLastSeqNum = result.LastSeqNo
w.PartitionID = result.PartitionID
w.CodecsFromServer = result.SupportedCodecs
+
return nil
}
@@ -164,7 +168,7 @@ func (w *SingleStreamWriter) createInitRequest() rawtopicwriter.InitRequest {
ProducerID: w.cfg.producerID,
WriteSessionMeta: w.cfg.writerMeta,
Partitioning: w.cfg.defaultPartitioning,
- GetLastSeqNo: w.cfg.getAutoSeq,
+ GetLastSeqNo: w.cfg.getLastSeqNum,
}
}
@@ -178,16 +182,18 @@ func (w *SingleStreamWriter) receiveMessagesLoop(ctx context.Context) {
if err != nil {
err = xerrors.WithStackTrace(fmt.Errorf("ydb: failed to receive message from write stream: %w", err))
_ = w.close(ctx, err)
+
return
}
switch m := mess.(type) {
case *rawtopicwriter.WriteResult:
- if err = w.cfg.queue.AcksReceived(m.Acks); err != nil {
+ if err = w.cfg.queue.AcksReceived(m.Acks); err != nil && !errors.Is(err, errCloseClosedMessageQueue) {
reason := xerrors.WithStackTrace(err)
closeCtx, closeCtxCancel := xcontext.WithCancel(ctx)
closeCtxCancel()
_ = w.close(closeCtx, reason)
+
return
}
case *rawtopicwriter.UpdateTokenResponse:
@@ -211,12 +217,14 @@ func (w *SingleStreamWriter) sendMessagesFromQueueToStreamLoop(ctx context.Conte
messages, err := w.cfg.queue.GetMessagesForSend(ctx)
if err != nil {
_ = w.close(ctx, err)
+
return
}
targetCodec, err := w.Encoder.CompressMessages(messages)
if err != nil {
_ = w.close(ctx, err)
+
return
}
@@ -233,6 +241,7 @@ func (w *SingleStreamWriter) sendMessagesFromQueueToStreamLoop(ctx context.Conte
if err != nil {
err = xerrors.WithStackTrace(fmt.Errorf("ydb: error send message to topic stream: %w", err))
_ = w.close(ctx, err)
+
return
}
}
@@ -272,5 +281,6 @@ func (w *SingleStreamWriter) sendUpdateToken(ctx context.Context) (err error) {
req := &rawtopicwriter.UpdateTokenRequest{}
req.Token = token
+
return stream.Send(req)
}
diff --git a/internal/topic/topicwriterinternal/writer_single_stream_test.go b/internal/topic/topicwriterinternal/writer_single_stream_test.go
index 59e08bc53..d12d7068b 100644
--- a/internal/topic/topicwriterinternal/writer_single_stream_test.go
+++ b/internal/topic/topicwriterinternal/writer_single_stream_test.go
@@ -20,7 +20,7 @@ func TestWriterImpl_CreateInitMessage(t *testing.T) {
defaultPartitioning: rawtopicwriter.NewPartitioningPartitionID(5),
compressorCount: 1,
},
- getAutoSeq: true,
+ getLastSeqNum: true,
}
w := newSingleStreamWriterStopped(ctx, cfg)
expected := rawtopicwriter.InitRequest{
@@ -36,7 +36,7 @@ func TestWriterImpl_CreateInitMessage(t *testing.T) {
t.Run("WithoutGetLastSeq", func(t *testing.T) {
ctx := xtest.Context(t)
w := newSingleStreamWriterStopped(ctx,
- SingleStreamWriterConfig{getAutoSeq: false},
+ SingleStreamWriterConfig{getLastSeqNum: false},
)
require.False(t, w.createInitRequest().GetLastSeqNo)
})
diff --git a/internal/types/types.go b/internal/types/types.go
new file mode 100644
index 000000000..4942cd787
--- /dev/null
+++ b/internal/types/types.go
@@ -0,0 +1,948 @@
+package types
+
+import (
+ "fmt"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
+)
+
+type Type interface {
+ Yql() string
+ String() string
+
+ ToYDB(a *allocator.Allocator) *Ydb.Type
+ equalsTo(rhs Type) bool
+}
+
+func TypeToYDB(t Type, a *allocator.Allocator) *Ydb.Type {
+ return t.ToYDB(a)
+}
+
+func TypeFromYDB(x *Ydb.Type) Type {
+ switch v := x.GetType().(type) {
+ case *Ydb.Type_TypeId:
+ return primitiveTypeFromYDB(v.TypeId)
+
+ case *Ydb.Type_OptionalType:
+ return NewOptional(TypeFromYDB(v.OptionalType.GetItem()))
+
+ case *Ydb.Type_ListType:
+ return NewList(TypeFromYDB(v.ListType.GetItem()))
+
+ case *Ydb.Type_DecimalType:
+ d := v.DecimalType
+
+ return NewDecimal(d.GetPrecision(), d.GetScale())
+
+ case *Ydb.Type_TupleType:
+ t := v.TupleType
+
+ return NewTuple(FromYDB(t.GetElements())...)
+
+ case *Ydb.Type_StructType:
+ s := v.StructType
+
+ return NewStruct(StructFields(s.GetMembers())...)
+
+ case *Ydb.Type_DictType:
+ keyType, valueType := TypeFromYDB(v.DictType.GetKey()), TypeFromYDB(v.DictType.GetPayload())
+ if valueType.equalsTo(NewVoid()) {
+ return NewSet(keyType)
+ }
+
+ return NewDict(keyType, valueType)
+
+ case *Ydb.Type_VariantType:
+ t := v.VariantType
+ switch x := t.GetType().(type) {
+ case *Ydb.VariantType_TupleItems:
+ return NewVariantTuple(FromYDB(x.TupleItems.GetElements())...)
+ case *Ydb.VariantType_StructItems:
+ return NewVariantStruct(StructFields(x.StructItems.GetMembers())...)
+ default:
+ panic("ydb: unknown variant type")
+ }
+
+ case *Ydb.Type_VoidType:
+ return NewVoid()
+
+ case *Ydb.Type_NullType:
+ return NewNull()
+
+ case *Ydb.Type_PgType:
+ return &PgType{
+ OID: x.GetPgType().GetOid(),
+ }
+
+ default:
+ panic("ydb: unknown type")
+ }
+}
+
+func primitiveTypeFromYDB(t Ydb.Type_PrimitiveTypeId) Type {
+ switch t {
+ case Ydb.Type_BOOL:
+ return Bool
+ case Ydb.Type_INT8:
+ return Int8
+ case Ydb.Type_UINT8:
+ return Uint8
+ case Ydb.Type_INT16:
+ return Int16
+ case Ydb.Type_UINT16:
+ return Uint16
+ case Ydb.Type_INT32:
+ return Int32
+ case Ydb.Type_UINT32:
+ return Uint32
+ case Ydb.Type_INT64:
+ return Int64
+ case Ydb.Type_UINT64:
+ return Uint64
+ case Ydb.Type_FLOAT:
+ return Float
+ case Ydb.Type_DOUBLE:
+ return Double
+ case Ydb.Type_DATE:
+ return Date
+ case Ydb.Type_DATETIME:
+ return Datetime
+ case Ydb.Type_TIMESTAMP:
+ return Timestamp
+ case Ydb.Type_INTERVAL:
+ return Interval
+ case Ydb.Type_TZ_DATE:
+ return TzDate
+ case Ydb.Type_TZ_DATETIME:
+ return TzDatetime
+ case Ydb.Type_TZ_TIMESTAMP:
+ return TzTimestamp
+ case Ydb.Type_STRING:
+ return Bytes
+ case Ydb.Type_UTF8:
+ return Text
+ case Ydb.Type_YSON:
+ return YSON
+ case Ydb.Type_JSON:
+ return JSON
+ case Ydb.Type_UUID:
+ return UUID
+ case Ydb.Type_JSON_DOCUMENT:
+ return JSONDocument
+ case Ydb.Type_DYNUMBER:
+ return DyNumber
+ default:
+ panic("ydb: unexpected type")
+ }
+}
+
+func FromYDB(es []*Ydb.Type) []Type {
+ ts := make([]Type, len(es))
+ for i, el := range es {
+ ts[i] = TypeFromYDB(el)
+ }
+
+ return ts
+}
+
+func Equal(a, b Type) bool {
+ return a.equalsTo(b)
+}
+
+type Decimal struct {
+ precision uint32
+ scale uint32
+}
+
+func (v *Decimal) Precision() uint32 {
+ return v.precision
+}
+
+func (v *Decimal) Scale() uint32 {
+ return v.scale
+}
+
+func (v *Decimal) String() string {
+ return v.Yql()
+}
+
+func (v *Decimal) Name() string {
+ return "Decimal"
+}
+
+func (v *Decimal) Yql() string {
+ return fmt.Sprintf("%s(%d,%d)", v.Name(), v.precision, v.scale)
+}
+
+func (v *Decimal) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(*Decimal)
+
+ return ok && *v == *vv
+}
+
+func (v *Decimal) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ decimal := a.Decimal()
+
+ decimal.Scale = v.scale
+ decimal.Precision = v.precision
+
+ typeDecimal := a.TypeDecimal()
+ typeDecimal.DecimalType = decimal
+
+ t := a.Type()
+ t.Type = typeDecimal
+
+ return t
+}
+
+func NewDecimal(precision, scale uint32) *Decimal {
+ return &Decimal{
+ precision: precision,
+ scale: scale,
+ }
+}
+
+type Dict struct {
+ keyType Type
+ valueType Type
+}
+
+func (v *Dict) KeyType() Type {
+ return v.keyType
+}
+
+func (v *Dict) ValueType() Type {
+ return v.valueType
+}
+
+func (v *Dict) String() string {
+ return v.Yql()
+}
+
+func (v *Dict) Yql() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ buffer.WriteString("Dict<")
+ buffer.WriteString(v.keyType.Yql())
+ buffer.WriteByte(',')
+ buffer.WriteString(v.valueType.Yql())
+ buffer.WriteByte('>')
+
+ return buffer.String()
+}
+
+func (v *Dict) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(*Dict)
+ if !ok {
+ return false
+ }
+ if !v.keyType.equalsTo(vv.keyType) {
+ return false
+ }
+ if !v.valueType.equalsTo(vv.valueType) {
+ return false
+ }
+
+ return true
+}
+
+func (v *Dict) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ typeDict := a.TypeDict()
+
+ typeDict.DictType = a.Dict()
+
+ typeDict.DictType.Key = v.keyType.ToYDB(a)
+ typeDict.DictType.Payload = v.valueType.ToYDB(a)
+
+ t.Type = typeDict
+
+ return t
+}
+
+func NewDict(key, value Type) (v *Dict) {
+ return &Dict{
+ keyType: key,
+ valueType: value,
+ }
+}
+
+type EmptyList struct{}
+
+func (v EmptyList) Yql() string {
+ return "EmptyList"
+}
+
+func (v EmptyList) String() string {
+ return v.Yql()
+}
+
+func (EmptyList) equalsTo(rhs Type) bool {
+ _, ok := rhs.(EmptyList)
+
+ return ok
+}
+
+func (EmptyList) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ t.Type = a.TypeEmptyList()
+
+ return t
+}
+
+func NewEmptyList() EmptyList {
+ return EmptyList{}
+}
+
+type EmptyDict struct{}
+
+func (v EmptyDict) String() string {
+ return v.Yql()
+}
+
+func (v EmptyDict) Yql() string {
+ return "EmptyDict"
+}
+
+func (EmptyDict) equalsTo(rhs Type) bool {
+ _, ok := rhs.(EmptyDict)
+
+ return ok
+}
+
+func (EmptyDict) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ t.Type = a.TypeEmptyDict()
+
+ return t
+}
+
+func EmptySet() EmptyDict {
+ return EmptyDict{}
+}
+
+func NewEmptyDict() EmptyDict {
+ return EmptyDict{}
+}
+
+type List struct {
+ itemType Type
+}
+
+func (v *List) ItemType() Type {
+ return v.itemType
+}
+
+func (v *List) String() string {
+ return v.Yql()
+}
+
+func (v *List) Yql() string {
+ return "List<" + v.itemType.Yql() + ">"
+}
+
+func (v *List) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(*List)
+ if !ok {
+ return false
+ }
+
+ return v.itemType.equalsTo(vv.itemType)
+}
+
+func (v *List) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ list := a.List()
+
+ list.Item = v.itemType.ToYDB(a)
+
+ typeList := a.TypeList()
+ typeList.ListType = list
+
+ t.Type = typeList
+
+ return t
+}
+
+func NewList(t Type) *List {
+ return &List{
+ itemType: t,
+ }
+}
+
+type Set struct {
+ itemType Type
+}
+
+func (v *Set) ItemType() Type {
+ return v.itemType
+}
+
+func (v *Set) String() string {
+ return v.Yql()
+}
+
+func (v *Set) Yql() string {
+ return "Set<" + v.itemType.Yql() + ">"
+}
+
+func (v *Set) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(*Set)
+ if !ok {
+ return false
+ }
+
+ return v.itemType.equalsTo(vv.itemType)
+}
+
+func (v *Set) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ typeDict := a.TypeDict()
+
+ typeDict.DictType = a.Dict()
+
+ typeDict.DictType.Key = v.itemType.ToYDB(a)
+ typeDict.DictType.Payload = _voidType
+
+ t.Type = typeDict
+
+ return t
+}
+
+func NewSet(t Type) *Set {
+ return &Set{
+ itemType: t,
+ }
+}
+
+type Optional struct {
+ innerType Type
+}
+
+func (v Optional) IsOptional() {}
+
+func (v Optional) InnerType() Type {
+ return v.innerType
+}
+
+func (v Optional) String() string {
+ return v.Yql()
+}
+
+func (v Optional) Yql() string {
+ return "Optional<" + v.innerType.Yql() + ">"
+}
+
+func (v Optional) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(Optional)
+ if !ok {
+ return false
+ }
+
+ return v.innerType.equalsTo(vv.innerType)
+}
+
+func (v Optional) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ typeOptional := a.TypeOptional()
+
+ typeOptional.OptionalType = a.Optional()
+
+ typeOptional.OptionalType.Item = v.innerType.ToYDB(a)
+
+ t.Type = typeOptional
+
+ return t
+}
+
+func NewOptional(t Type) Optional {
+ return Optional{
+ innerType: t,
+ }
+}
+
+type PgType struct {
+ OID uint32
+}
+
+func (v PgType) String() string {
+ return v.Yql()
+}
+
+func (v PgType) Yql() string {
+ return fmt.Sprintf("PgType(%v)", v.OID)
+}
+
+func (v PgType) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ //nolint:godox
+ // TODO: make allocator
+ return &Ydb.Type{Type: &Ydb.Type_PgType{
+ PgType: &Ydb.PgType{
+ Oid: v.OID,
+ },
+ }}
+}
+
+func (v PgType) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(PgType)
+ if !ok {
+ return false
+ }
+
+ return v.OID == vv.OID
+}
+
+type Primitive uint
+
+func (v Primitive) String() string {
+ return v.Yql()
+}
+
+func (v Primitive) Yql() string {
+ return primitiveString[v]
+}
+
+const (
+ Unknown Primitive = iota
+ Bool
+ Int8
+ Uint8
+ Int16
+ Uint16
+ Int32
+ Uint32
+ Int64
+ Uint64
+ Float
+ Double
+ Date
+ Datetime
+ Timestamp
+ Interval
+ TzDate
+ TzDatetime
+ TzTimestamp
+ Bytes
+ Text
+ YSON
+ JSON
+ UUID
+ JSONDocument
+ DyNumber
+)
+
+var primitive = [...]*Ydb.Type{
+ Bool: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL}},
+ Int8: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8}},
+ Uint8: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8}},
+ Int16: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16}},
+ Uint16: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16}},
+ Int32: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32}},
+ Uint32: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32}},
+ Int64: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64}},
+ Uint64: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64}},
+ Float: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT}},
+ Double: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE}},
+ Date: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE}},
+ Datetime: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME}},
+ Timestamp: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP}},
+ Interval: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL}},
+ TzDate: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE}},
+ TzDatetime: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME}},
+ TzTimestamp: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP}},
+ Bytes: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING}},
+ Text: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8}},
+ YSON: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON}},
+ JSON: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON}},
+ UUID: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID}},
+ JSONDocument: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT}},
+ DyNumber: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DYNUMBER}},
+}
+
+var primitiveString = [...]string{
+ Unknown: "",
+ Bool: "Bool",
+ Int8: "Int8",
+ Uint8: "Uint8",
+ Int16: "Int16",
+ Uint16: "Uint16",
+ Int32: "Int32",
+ Uint32: "Uint32",
+ Int64: "Int64",
+ Uint64: "Uint64",
+ Float: "Float",
+ Double: "Double",
+ Date: "Date",
+ Datetime: "Datetime",
+ Timestamp: "Timestamp",
+ Interval: "Interval",
+ TzDate: "TzDate",
+ TzDatetime: "TzDatetime",
+ TzTimestamp: "TzTimestamp",
+ Bytes: "String",
+ Text: "Utf8",
+ YSON: "Yson",
+ JSON: "Json",
+ UUID: "Uuid",
+ JSONDocument: "JsonDocument",
+ DyNumber: "DyNumber",
+}
+
+func (v Primitive) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(Primitive)
+ if !ok {
+ return false
+ }
+
+ return v == vv
+}
+
+func (v Primitive) ToYDB(*allocator.Allocator) *Ydb.Type {
+ return primitive[v]
+}
+
+type (
+ StructField struct {
+ Name string
+ T Type
+ }
+ Struct struct {
+ fields []StructField
+ }
+)
+
+func (v *Struct) Field(i int) StructField {
+ return v.fields[i]
+}
+
+func (v *Struct) Fields() []StructField {
+ return v.fields
+}
+
+func (v *Struct) String() string {
+ return v.Yql()
+}
+
+func (v *Struct) Yql() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ buffer.WriteString("Struct<")
+ for i := range v.fields {
+ if i > 0 {
+ buffer.WriteByte(',')
+ }
+ buffer.WriteString("'" + v.fields[i].Name + "'")
+ buffer.WriteByte(':')
+ buffer.WriteString(v.fields[i].T.Yql())
+ }
+ buffer.WriteByte('>')
+
+ return buffer.String()
+}
+
+func (v *Struct) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(*Struct)
+ if !ok {
+ return false
+ }
+ if len(v.fields) != len(vv.fields) {
+ return false
+ }
+ for i := range v.fields {
+ if v.fields[i].Name != vv.fields[i].Name {
+ return false
+ }
+ if !v.fields[i].T.equalsTo(vv.fields[i].T) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (v *Struct) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ typeStruct := a.TypeStruct()
+
+ typeStruct.StructType = a.Struct()
+
+ for i := range v.fields {
+ structMember := a.StructMember()
+ structMember.Name = v.fields[i].Name
+ structMember.Type = v.fields[i].T.ToYDB(a)
+ typeStruct.StructType.Members = append(
+ typeStruct.StructType.GetMembers(),
+ structMember,
+ )
+ }
+
+ t.Type = typeStruct
+
+ return t
+}
+
+func NewStruct(fields ...StructField) (v *Struct) {
+ return &Struct{
+ fields: fields,
+ }
+}
+
+func StructFields(ms []*Ydb.StructMember) []StructField {
+ fs := make([]StructField, len(ms))
+ for i, m := range ms {
+ fs[i] = StructField{
+ Name: m.GetName(),
+ T: TypeFromYDB(m.GetType()),
+ }
+ }
+
+ return fs
+}
+
+type Tuple struct {
+ innerTypes []Type
+}
+
+func (v *Tuple) InnerTypes() []Type {
+ return v.innerTypes
+}
+
+func (v *Tuple) ItemType(i int) Type {
+ return v.innerTypes[i]
+}
+
+func (v *Tuple) String() string {
+ return v.Yql()
+}
+
+func (v *Tuple) Yql() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ buffer.WriteString("Tuple<")
+ for i, t := range v.innerTypes {
+ if i > 0 {
+ buffer.WriteByte(',')
+ }
+ buffer.WriteString(t.Yql())
+ }
+ buffer.WriteByte('>')
+
+ return buffer.String()
+}
+
+func (v *Tuple) equalsTo(rhs Type) bool {
+ vv, ok := rhs.(*Tuple)
+ if !ok {
+ return false
+ }
+ if len(v.innerTypes) != len(vv.innerTypes) {
+ return false
+ }
+ for i := range v.innerTypes {
+ if !v.innerTypes[i].equalsTo(vv.innerTypes[i]) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (v *Tuple) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ var items []Type
+ if v != nil {
+ items = v.innerTypes
+ }
+ t := a.Type()
+
+ typeTuple := a.TypeTuple()
+
+ typeTuple.TupleType = a.Tuple()
+
+ for _, vv := range items {
+ typeTuple.TupleType.Elements = append(typeTuple.TupleType.GetElements(), vv.ToYDB(a))
+ }
+
+ t.Type = typeTuple
+
+ return t
+}
+
+func NewTuple(items ...Type) (v *Tuple) {
+ return &Tuple{
+ innerTypes: items,
+ }
+}
+
+type VariantStruct struct {
+ *Struct
+}
+
+func (v *VariantStruct) Yql() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ buffer.WriteString("Variant<")
+ for i := range v.fields {
+ if i > 0 {
+ buffer.WriteByte(',')
+ }
+ buffer.WriteString("'" + v.fields[i].Name + "'")
+ buffer.WriteByte(':')
+ buffer.WriteString(v.fields[i].T.Yql())
+ }
+ buffer.WriteByte('>')
+
+ return buffer.String()
+}
+
+func (v *VariantStruct) equalsTo(rhs Type) bool {
+ switch t := rhs.(type) {
+ case *VariantStruct:
+ return v.Struct.equalsTo(t.Struct)
+ case *Struct:
+ return v.Struct.equalsTo(t)
+ default:
+ return false
+ }
+}
+
+func (v *VariantStruct) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ typeVariant := a.TypeVariant()
+
+ typeVariant.VariantType = a.Variant()
+
+ structItems := a.VariantStructItems()
+ structItems.StructItems = v.Struct.ToYDB(a).GetType().(*Ydb.Type_StructType).StructType
+
+ typeVariant.VariantType.Type = structItems
+
+ t.Type = typeVariant
+
+ return t
+}
+
+func NewVariantStruct(fields ...StructField) *VariantStruct {
+ return &VariantStruct{
+ Struct: NewStruct(fields...),
+ }
+}
+
+type VariantTuple struct {
+ *Tuple
+}
+
+func (v *VariantTuple) Yql() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ buffer.WriteString("Variant<")
+ for i, t := range v.innerTypes {
+ if i > 0 {
+ buffer.WriteByte(',')
+ }
+ buffer.WriteString(t.Yql())
+ }
+ buffer.WriteByte('>')
+
+ return buffer.String()
+}
+
+func (v *VariantTuple) equalsTo(rhs Type) bool {
+ switch t := rhs.(type) {
+ case *VariantTuple:
+ return v.Tuple.equalsTo(t.Tuple)
+ case *Tuple:
+ return v.Tuple.equalsTo(t)
+ default:
+ return false
+ }
+}
+
+func (v *VariantTuple) ToYDB(a *allocator.Allocator) *Ydb.Type {
+ t := a.Type()
+
+ typeVariant := a.TypeVariant()
+
+ typeVariant.VariantType = a.Variant()
+
+ tupleItems := a.VariantTupleItems()
+ tupleItems.TupleItems = v.Tuple.ToYDB(a).GetType().(*Ydb.Type_TupleType).TupleType
+
+ typeVariant.VariantType.Type = tupleItems
+
+ t.Type = typeVariant
+
+ return t
+}
+
+func NewVariantTuple(items ...Type) *VariantTuple {
+ return &VariantTuple{
+ Tuple: NewTuple(items...),
+ }
+}
+
+type Void struct{}
+
+func (v Void) String() string {
+ return v.Yql()
+}
+
+func (v Void) Yql() string {
+ return "Void"
+}
+
+var _voidType = &Ydb.Type{
+ Type: &Ydb.Type_VoidType{},
+}
+
+func (v Void) equalsTo(rhs Type) bool {
+ _, ok := rhs.(Void)
+
+ return ok
+}
+
+func (Void) ToYDB(*allocator.Allocator) *Ydb.Type {
+ return _voidType
+}
+
+func NewVoid() Void {
+ return Void{}
+}
+
+type Null struct{}
+
+func (v Null) String() string {
+ return v.Yql()
+}
+
+func (v Null) Yql() string {
+ return "Null"
+}
+
+var _nullType = &Ydb.Type{
+ Type: &Ydb.Type_NullType{},
+}
+
+func (v Null) equalsTo(rhs Type) bool {
+ _, ok := rhs.(Null)
+
+ return ok
+}
+
+func (Null) ToYDB(*allocator.Allocator) *Ydb.Type {
+ return _nullType
+}
+
+func NewNull() Null {
+ return Null{}
+}
diff --git a/internal/types/types_test.go b/internal/types/types_test.go
new file mode 100644
index 000000000..3c9936a2a
--- /dev/null
+++ b/internal/types/types_test.go
@@ -0,0 +1,381 @@
+package types
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pg"
+)
+
+func TestTypeToString(t *testing.T) {
+ for _, tt := range []struct {
+ t Type
+ s string
+ }{
+ {
+ t: NewVoid(),
+ s: "Void",
+ },
+ {
+ t: NewNull(),
+ s: "Null",
+ },
+ {
+ t: Bool,
+ s: "Bool",
+ },
+ {
+ t: Int8,
+ s: "Int8",
+ },
+ {
+ t: Uint8,
+ s: "Uint8",
+ },
+ {
+ t: Int16,
+ s: "Int16",
+ },
+ {
+ t: Uint16,
+ s: "Uint16",
+ },
+ {
+ t: Int32,
+ s: "Int32",
+ },
+ {
+ t: Uint32,
+ s: "Uint32",
+ },
+ {
+ t: Int64,
+ s: "Int64",
+ },
+ {
+ t: Uint64,
+ s: "Uint64",
+ },
+ {
+ t: Float,
+ s: "Float",
+ },
+ {
+ t: Double,
+ s: "Double",
+ },
+ {
+ t: Date,
+ s: "Date",
+ },
+ {
+ t: Datetime,
+ s: "Datetime",
+ },
+ {
+ t: Timestamp,
+ s: "Timestamp",
+ },
+ {
+ t: Interval,
+ s: "Interval",
+ },
+ {
+ t: TzDate,
+ s: "TzDate",
+ },
+ {
+ t: TzDatetime,
+ s: "TzDatetime",
+ },
+ {
+ t: TzTimestamp,
+ s: "TzTimestamp",
+ },
+ {
+ t: Bytes,
+ s: "String",
+ },
+ {
+ t: Text,
+ s: "Utf8",
+ },
+ {
+ t: YSON,
+ s: "Yson",
+ },
+ {
+ t: JSON,
+ s: "Json",
+ },
+ {
+ t: UUID,
+ s: "Uuid",
+ },
+ {
+ t: JSONDocument,
+ s: "JsonDocument",
+ },
+ {
+ t: DyNumber,
+ s: "DyNumber",
+ },
+ {
+ t: NewOptional(Bool),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Int8),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Uint8),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Int16),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Uint16),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Int32),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Uint32),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Int64),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Uint64),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Float),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Double),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Date),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Datetime),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Timestamp),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Interval),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(TzDate),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(TzDatetime),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(TzTimestamp),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Bytes),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(Text),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(YSON),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(JSON),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(UUID),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(JSONDocument),
+ s: "Optional",
+ },
+ {
+ t: NewOptional(DyNumber),
+ s: "Optional",
+ },
+ {
+ t: NewDecimal(22, 9),
+ s: "Decimal(22,9)",
+ },
+ {
+ t: NewDict(Text, Timestamp),
+ s: "Dict",
+ },
+ {
+ t: NewEmptyList(),
+ s: "EmptyList",
+ },
+ {
+ t: NewList(Uint32),
+ s: "List",
+ },
+ {
+ t: NewSet(Uint32),
+ s: "Set",
+ },
+ {
+ t: EmptySet(),
+ s: "EmptyDict",
+ },
+ {
+ t: NewEmptyDict(),
+ s: "EmptyDict",
+ },
+ {
+ t: NewVariantStruct(
+ StructField{
+ Name: "a",
+ T: Bool,
+ },
+ StructField{
+ Name: "b",
+ T: Float,
+ },
+ ),
+ s: "Variant<'a':Bool,'b':Float>",
+ },
+ {
+ t: NewVariantTuple(
+ Bool,
+ Float,
+ ),
+ s: "Variant",
+ },
+ {
+ t: PgType{OID: pg.OIDUnknown},
+ s: "PgType(705)",
+ },
+ } {
+ t.Run(tt.s, func(t *testing.T) {
+ if got := tt.t.Yql(); got != tt.s {
+ t.Errorf("s representations not equals:\n\n - got: %s\n\n - want: %s", got, tt.s)
+ }
+ })
+ }
+}
+
+func TestEqual(t *testing.T) {
+ tests := []struct {
+ lhs Type
+ rhs Type
+ equal bool
+ }{
+ {
+ Bool,
+ Bool,
+ true,
+ },
+ {
+ Bool,
+ Text,
+ false,
+ },
+ {
+ Text,
+ Text,
+ true,
+ },
+ {
+ NewOptional(Bool),
+ NewOptional(Bool),
+ true,
+ },
+ {
+ NewOptional(Bool),
+ NewOptional(Text),
+ false,
+ },
+ {
+ NewOptional(Text),
+ NewOptional(Text),
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run("", func(t *testing.T) {
+ if equal := Equal(tt.lhs, tt.rhs); equal != tt.equal {
+ t.Errorf("Equal(%s, %s) = %v, want %v", tt.lhs, tt.rhs, equal, tt.equal)
+ }
+ })
+ }
+}
+
+func TestOptionalInnerType(t *testing.T) {
+ tests := []struct {
+ src Type
+ innerType Type
+ isOptional bool
+ }{
+ {
+ Bool,
+ nil,
+ false,
+ },
+ {
+ Text,
+ nil,
+ false,
+ },
+ {
+ NewOptional(Bool),
+ Bool,
+ true,
+ },
+ {
+ NewOptional(Text),
+ Text,
+ true,
+ },
+ {
+ NewOptional(NewTuple(Text, Bool, Uint64, NewOptional(Int64))),
+ NewTuple(Text, Bool, Uint64, NewOptional(Int64)),
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run("", func(t *testing.T) {
+ optional, isOptional := tt.src.(interface {
+ IsOptional()
+ InnerType() Type
+ })
+ require.Equal(t, tt.isOptional, isOptional)
+ var innerType Type
+ if isOptional {
+ innerType = optional.InnerType()
+ }
+ if tt.innerType == nil {
+ require.Nil(t, innerType)
+ } else {
+ require.True(t, Equal(tt.innerType, innerType))
+ }
+ })
+ }
+}
diff --git a/internal/value/errors.go b/internal/value/errors.go
new file mode 100644
index 000000000..0c3212bbf
--- /dev/null
+++ b/internal/value/errors.go
@@ -0,0 +1,8 @@
+package value
+
+import "errors"
+
+var (
+ ErrCannotCast = errors.New("cannot cast")
+ errDestinationTypeIsNotAPointer = errors.New("destination type is not a pointer")
+)
diff --git a/internal/value/nullable.go b/internal/value/nullable.go
new file mode 100644
index 000000000..1553d3eb1
--- /dev/null
+++ b/internal/value/nullable.go
@@ -0,0 +1,450 @@
+package value
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
+)
+
+func NullableBoolValue(v *bool) Value {
+ if v == nil {
+ return NullValue(types.Bool)
+ }
+
+ return OptionalValue(BoolValue(*v))
+}
+
+func NullableInt8Value(v *int8) Value {
+ if v == nil {
+ return NullValue(types.Int8)
+ }
+
+ return OptionalValue(Int8Value(*v))
+}
+
+func NullableInt16Value(v *int16) Value {
+ if v == nil {
+ return NullValue(types.Int16)
+ }
+
+ return OptionalValue(Int16Value(*v))
+}
+
+func NullableInt32Value(v *int32) Value {
+ if v == nil {
+ return NullValue(types.Int32)
+ }
+
+ return OptionalValue(Int32Value(*v))
+}
+
+func NullableInt64Value(v *int64) Value {
+ if v == nil {
+ return NullValue(types.Int64)
+ }
+
+ return OptionalValue(Int64Value(*v))
+}
+
+func NullableUint8Value(v *uint8) Value {
+ if v == nil {
+ return NullValue(types.Uint8)
+ }
+
+ return OptionalValue(Uint8Value(*v))
+}
+
+func NullableUint16Value(v *uint16) Value {
+ if v == nil {
+ return NullValue(types.Uint16)
+ }
+
+ return OptionalValue(Uint16Value(*v))
+}
+
+func NullableUint32Value(v *uint32) Value {
+ if v == nil {
+ return NullValue(types.Uint32)
+ }
+
+ return OptionalValue(Uint32Value(*v))
+}
+
+func NullableUint64Value(v *uint64) Value {
+ if v == nil {
+ return NullValue(types.Uint64)
+ }
+
+ return OptionalValue(Uint64Value(*v))
+}
+
+func NullableFloatValue(v *float32) Value {
+ if v == nil {
+ return NullValue(types.Float)
+ }
+
+ return OptionalValue(FloatValue(*v))
+}
+
+func NullableDoubleValue(v *float64) Value {
+ if v == nil {
+ return NullValue(types.Double)
+ }
+
+ return OptionalValue(DoubleValue(*v))
+}
+
+func NullableDateValue(v *uint32) Value {
+ if v == nil {
+ return NullValue(types.Date)
+ }
+
+ return OptionalValue(DateValue(*v))
+}
+
+func NullableDateValueFromTime(v *time.Time) Value {
+ if v == nil {
+ return NullValue(types.Date)
+ }
+
+ return OptionalValue(DateValueFromTime(*v))
+}
+
+func NullableDatetimeValue(v *uint32) Value {
+ if v == nil {
+ return NullValue(types.Datetime)
+ }
+
+ return OptionalValue(DatetimeValue(*v))
+}
+
+func NullableDatetimeValueFromTime(v *time.Time) Value {
+ if v == nil {
+ return NullValue(types.Datetime)
+ }
+
+ return OptionalValue(DatetimeValueFromTime(*v))
+}
+
+func NullableTzDateValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.TzDate)
+ }
+
+ return OptionalValue(TzDateValue(*v))
+}
+
+func NullableTzDateValueFromTime(v *time.Time) Value {
+ if v == nil {
+ return NullValue(types.TzDate)
+ }
+
+ return OptionalValue(TzDateValueFromTime(*v))
+}
+
+func NullableTzDatetimeValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.TzDatetime)
+ }
+
+ return OptionalValue(TzDatetimeValue(*v))
+}
+
+func NullableTzDatetimeValueFromTime(v *time.Time) Value {
+ if v == nil {
+ return NullValue(types.TzDatetime)
+ }
+
+ return OptionalValue(TzDatetimeValueFromTime(*v))
+}
+
+func NullableTimestampValue(v *uint64) Value {
+ if v == nil {
+ return NullValue(types.Timestamp)
+ }
+
+ return OptionalValue(TimestampValue(*v))
+}
+
+func NullableTimestampValueFromTime(v *time.Time) Value {
+ if v == nil {
+ return NullValue(types.Timestamp)
+ }
+
+ return OptionalValue(TimestampValueFromTime(*v))
+}
+
+func NullableTzTimestampValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.TzTimestamp)
+ }
+
+ return OptionalValue(TzTimestampValue(*v))
+}
+
+func NullableTzTimestampValueFromTime(v *time.Time) Value {
+ if v == nil {
+ return NullValue(types.TzTimestamp)
+ }
+
+ return OptionalValue(TzTimestampValueFromTime(*v))
+}
+
+func NullableIntervalValueFromMicroseconds(v *int64) Value {
+ if v == nil {
+ return NullValue(types.Interval)
+ }
+
+ return OptionalValue(IntervalValue(*v))
+}
+
+func NullableIntervalValueFromDuration(v *time.Duration) Value {
+ if v == nil {
+ return NullValue(types.Interval)
+ }
+
+ return OptionalValue(IntervalValueFromDuration(*v))
+}
+
+func NullableBytesValue(v *[]byte) Value {
+ if v == nil {
+ return NullValue(types.Bytes)
+ }
+
+ return OptionalValue(BytesValue(*v))
+}
+
+func NullableBytesValueFromString(v *string) Value {
+ if v == nil {
+ return NullValue(types.Bytes)
+ }
+
+ return OptionalValue(BytesValue(xstring.ToBytes(*v)))
+}
+
+func NullableTextValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.Text)
+ }
+
+ return OptionalValue(TextValue(*v))
+}
+
+func NullableYSONValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.YSON)
+ }
+
+ return OptionalValue(YSONValue(xstring.ToBytes(*v)))
+}
+
+func NullableYSONValueFromBytes(v *[]byte) Value {
+ if v == nil {
+ return NullValue(types.YSON)
+ }
+
+ return OptionalValue(YSONValue(*v))
+}
+
+func NullableJSONValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.JSON)
+ }
+
+ return OptionalValue(JSONValue(*v))
+}
+
+func NullableJSONValueFromBytes(v *[]byte) Value {
+ if v == nil {
+ return NullValue(types.JSON)
+ }
+
+ return OptionalValue(JSONValue(xstring.FromBytes(*v)))
+}
+
+func NullableUUIDValue(v *[16]byte) Value {
+ if v == nil {
+ return NullValue(types.UUID)
+ }
+
+ return OptionalValue(UUIDValue(*v))
+}
+
+func NullableJSONDocumentValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.JSONDocument)
+ }
+
+ return OptionalValue(JSONDocumentValue(*v))
+}
+
+func NullableJSONDocumentValueFromBytes(v *[]byte) Value {
+ if v == nil {
+ return NullValue(types.JSONDocument)
+ }
+
+ return OptionalValue(JSONDocumentValue(xstring.FromBytes(*v)))
+}
+
+func NullableDyNumberValue(v *string) Value {
+ if v == nil {
+ return NullValue(types.DyNumber)
+ }
+
+ return OptionalValue(DyNumberValue(*v))
+}
+
+// Nullable makes optional value from nullable type
+// Warning: type interface will be replaced in the future with typed parameters pattern from go1.18
+//
+//nolint:gocyclo
+func Nullable(t types.Type, v interface{}) Value {
+ switch t {
+ case types.Bool:
+ return NullableBoolValue(v.(*bool))
+ case types.Int8:
+ return NullableInt8Value(v.(*int8))
+ case types.Uint8:
+ return NullableUint8Value(v.(*uint8))
+ case types.Int16:
+ return NullableInt16Value(v.(*int16))
+ case types.Uint16:
+ return NullableUint16Value(v.(*uint16))
+ case types.Int32:
+ return NullableInt32Value(v.(*int32))
+ case types.Uint32:
+ return NullableUint32Value(v.(*uint32))
+ case types.Int64:
+ return NullableInt64Value(v.(*int64))
+ case types.Uint64:
+ return NullableUint64Value(v.(*uint64))
+ case types.Float:
+ return NullableFloatValue(v.(*float32))
+ case types.Double:
+ return NullableDoubleValue(v.(*float64))
+ case types.Date:
+ switch tt := v.(type) {
+ case *uint32:
+ return NullableDateValue(tt)
+ case *time.Time:
+ return NullableDateValueFromTime(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeDate", tt))
+ }
+ case types.Datetime:
+ switch tt := v.(type) {
+ case *uint32:
+ return NullableDatetimeValue(tt)
+ case *time.Time:
+ return NullableDatetimeValueFromTime(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeDatetime", tt))
+ }
+ case types.Timestamp:
+ switch tt := v.(type) {
+ case *uint64:
+ return NullableTimestampValue(tt)
+ case *time.Time:
+ return NullableTimestampValueFromTime(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeTimestamp", tt))
+ }
+ case types.Interval:
+ switch tt := v.(type) {
+ case *int64:
+ return NullableIntervalValueFromMicroseconds(tt)
+ case *time.Duration:
+ return NullableIntervalValueFromDuration(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeInterval", tt))
+ }
+ case types.TzDate:
+ switch tt := v.(type) {
+ case *string:
+ return NullableTzDateValue(tt)
+ case *time.Time:
+ return NullableTzDateValueFromTime(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeTzDate", tt))
+ }
+ case types.TzDatetime:
+ switch tt := v.(type) {
+ case *string:
+ return NullableTzDatetimeValue(tt)
+ case *time.Time:
+ return NullableTzDatetimeValueFromTime(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeTzDatetime", tt))
+ }
+ case types.TzTimestamp:
+ switch tt := v.(type) {
+ case *string:
+ return NullableTzTimestampValue(tt)
+ case *time.Time:
+ return NullableTzTimestampValueFromTime(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeTzTimestamp", tt))
+ }
+ case types.Bytes:
+ switch tt := v.(type) {
+ case *[]byte:
+ return NullableBytesValue(tt)
+ case *string:
+ return NullableBytesValueFromString(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeBytes", tt))
+ }
+ case types.Text:
+ switch tt := v.(type) {
+ case *string:
+ return NullableTextValue(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeText", tt))
+ }
+ case types.YSON:
+ switch tt := v.(type) {
+ case *string:
+ return NullableYSONValue(tt)
+ case *[]byte:
+ return NullableYSONValueFromBytes(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeYSON", tt))
+ }
+ case types.JSON:
+ switch tt := v.(type) {
+ case *string:
+ return NullableJSONValue(tt)
+ case *[]byte:
+ return NullableJSONValueFromBytes(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeJSON", tt))
+ }
+ case types.UUID:
+ switch tt := v.(type) {
+ case *[16]byte:
+ return NullableUUIDValue(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeUUID", tt))
+ }
+ case types.JSONDocument:
+ switch tt := v.(type) {
+ case *string:
+ return NullableJSONDocumentValue(tt)
+ case *[]byte:
+ return NullableJSONDocumentValueFromBytes(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeJSONDocument", tt))
+ }
+ case types.DyNumber:
+ switch tt := v.(type) {
+ case *string:
+ return NullableDyNumberValue(tt)
+ default:
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeDyNumber", tt))
+ }
+ default:
+ panic(fmt.Sprintf("unsupported type: %T", t))
+ }
+}
diff --git a/internal/value/time.go b/internal/value/time.go
index b840ddedc..37f7aa374 100644
--- a/internal/value/time.go
+++ b/internal/value/time.go
@@ -54,6 +54,7 @@ func DatetimeToTime(n uint32) time.Time {
func TimestampToTime(n uint64) time.Time {
sec := n / 1e6
nsec := (n - (sec * 1e6)) * 1000
+
return time.Unix(int64(sec), int64(nsec))
}
@@ -70,6 +71,7 @@ func TzDateToTime(s string) (t time.Time, err error) {
if err != nil {
return t, xerrors.WithStackTrace(fmt.Errorf("parse '%s' failed: %w", s, err))
}
+
return t, nil
}
@@ -86,6 +88,7 @@ func TzDatetimeToTime(s string) (t time.Time, err error) {
if err != nil {
return t, xerrors.WithStackTrace(fmt.Errorf("parse '%s' failed: %w", s, err))
}
+
return t, nil
}
@@ -106,5 +109,6 @@ func TzTimestampToTime(s string) (t time.Time, err error) {
if err != nil {
return t, xerrors.WithStackTrace(fmt.Errorf("parse '%s' failed: %w", s, err))
}
+
return t, nil
}
diff --git a/internal/value/time_test.go b/internal/value/time_test.go
index f9d93ac37..a1e0cfca2 100644
--- a/internal/value/time_test.go
+++ b/internal/value/time_test.go
@@ -20,6 +20,7 @@ func TestTzSomeToTime(t *testing.T) {
time.Date(2020, time.May, 29, 0, 0, 0, 0,
func() *time.Location {
l, _ := time.LoadLocation("Europe/Berlin")
+
return l
}(),
),
@@ -31,6 +32,7 @@ func TestTzSomeToTime(t *testing.T) {
time.Date(2020, time.May, 29, 11, 22, 54, 0,
func() *time.Location {
l, _ := time.LoadLocation("Europe/Berlin")
+
return l
}(),
),
@@ -42,6 +44,7 @@ func TestTzSomeToTime(t *testing.T) {
time.Date(2020, time.May, 29, 11, 22, 54, 123456000,
func() *time.Location {
l, _ := time.LoadLocation("Europe/Berlin")
+
return l
}(),
),
@@ -53,6 +56,7 @@ func TestTzSomeToTime(t *testing.T) {
time.Date(2020, time.May, 29, 11, 22, 54, 0,
func() *time.Location {
l, _ := time.LoadLocation("Europe/Berlin")
+
return l
}(),
),
diff --git a/internal/value/type.go b/internal/value/type.go
deleted file mode 100644
index 11ccb19b1..000000000
--- a/internal/value/type.go
+++ /dev/null
@@ -1,849 +0,0 @@
-package value
-
-import (
- "fmt"
-
- "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
-
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
-)
-
-type Type interface {
- Yql() string
- String() string
-
- toYDB(a *allocator.Allocator) *Ydb.Type
- equalsTo(rhs Type) bool
-}
-
-func TypeToYDB(t Type, a *allocator.Allocator) *Ydb.Type {
- return t.toYDB(a)
-}
-
-func TypeFromYDB(x *Ydb.Type) Type {
- switch v := x.Type.(type) {
- case *Ydb.Type_TypeId:
- return primitiveTypeFromYDB(v.TypeId)
-
- case *Ydb.Type_OptionalType:
- return Optional(TypeFromYDB(v.OptionalType.Item))
-
- case *Ydb.Type_ListType:
- return List(TypeFromYDB(v.ListType.Item))
-
- case *Ydb.Type_DecimalType:
- d := v.DecimalType
- return Decimal(d.Precision, d.Scale)
-
- case *Ydb.Type_TupleType:
- t := v.TupleType
- return Tuple(TypesFromYDB(t.Elements)...)
-
- case *Ydb.Type_StructType:
- s := v.StructType
- return Struct(StructFields(s.Members)...)
-
- case *Ydb.Type_DictType:
- keyType, valueType := TypeFromYDB(v.DictType.Key), TypeFromYDB(v.DictType.Payload)
- if valueType.equalsTo(Void()) {
- return Set(keyType)
- }
- return Dict(keyType, valueType)
-
- case *Ydb.Type_VariantType:
- t := v.VariantType
- switch x := t.Type.(type) {
- case *Ydb.VariantType_TupleItems:
- return VariantTuple(TypesFromYDB(x.TupleItems.Elements)...)
- case *Ydb.VariantType_StructItems:
- return VariantStruct(StructFields(x.StructItems.Members)...)
- default:
- panic("ydb: unknown variant type")
- }
-
- case *Ydb.Type_VoidType:
- return Void()
-
- case *Ydb.Type_NullType:
- return Null()
-
- default:
- panic("ydb: unknown type")
- }
-}
-
-func primitiveTypeFromYDB(t Ydb.Type_PrimitiveTypeId) Type {
- switch t {
- case Ydb.Type_BOOL:
- return TypeBool
- case Ydb.Type_INT8:
- return TypeInt8
- case Ydb.Type_UINT8:
- return TypeUint8
- case Ydb.Type_INT16:
- return TypeInt16
- case Ydb.Type_UINT16:
- return TypeUint16
- case Ydb.Type_INT32:
- return TypeInt32
- case Ydb.Type_UINT32:
- return TypeUint32
- case Ydb.Type_INT64:
- return TypeInt64
- case Ydb.Type_UINT64:
- return TypeUint64
- case Ydb.Type_FLOAT:
- return TypeFloat
- case Ydb.Type_DOUBLE:
- return TypeDouble
- case Ydb.Type_DATE:
- return TypeDate
- case Ydb.Type_DATETIME:
- return TypeDatetime
- case Ydb.Type_TIMESTAMP:
- return TypeTimestamp
- case Ydb.Type_INTERVAL:
- return TypeInterval
- case Ydb.Type_TZ_DATE:
- return TypeTzDate
- case Ydb.Type_TZ_DATETIME:
- return TypeTzDatetime
- case Ydb.Type_TZ_TIMESTAMP:
- return TypeTzTimestamp
- case Ydb.Type_STRING:
- return TypeBytes
- case Ydb.Type_UTF8:
- return TypeText
- case Ydb.Type_YSON:
- return TypeYSON
- case Ydb.Type_JSON:
- return TypeJSON
- case Ydb.Type_UUID:
- return TypeUUID
- case Ydb.Type_JSON_DOCUMENT:
- return TypeJSONDocument
- case Ydb.Type_DYNUMBER:
- return TypeDyNumber
- default:
- panic("ydb: unexpected type")
- }
-}
-
-func TypesFromYDB(es []*Ydb.Type) []Type {
- ts := make([]Type, len(es))
- for i, el := range es {
- ts[i] = TypeFromYDB(el)
- }
- return ts
-}
-
-func TypesEqual(a, b Type) bool {
- return a.equalsTo(b)
-}
-
-type DecimalType struct {
- Precision uint32
- Scale uint32
-}
-
-func (v *DecimalType) String() string {
- return v.Yql()
-}
-
-func (v *DecimalType) Name() string {
- return "Decimal"
-}
-
-func (v *DecimalType) Yql() string {
- return fmt.Sprintf("%s(%d,%d)", v.Name(), v.Precision, v.Scale)
-}
-
-func (v *DecimalType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(*DecimalType)
- return ok && *v == *vv
-}
-
-func (v *DecimalType) toYDB(a *allocator.Allocator) *Ydb.Type {
- decimal := a.Decimal()
-
- decimal.Scale = v.Scale
- decimal.Precision = v.Precision
-
- typeDecimal := a.TypeDecimal()
- typeDecimal.DecimalType = decimal
-
- t := a.Type()
- t.Type = typeDecimal
-
- return t
-}
-
-func Decimal(precision, scale uint32) *DecimalType {
- return &DecimalType{
- Precision: precision,
- Scale: scale,
- }
-}
-
-type dictType struct {
- keyType Type
- valueType Type
-}
-
-func (v *dictType) String() string {
- return v.Yql()
-}
-
-func (v *dictType) Yql() string {
- buffer := xstring.Buffer()
- defer buffer.Free()
- buffer.WriteString("Dict<")
- buffer.WriteString(v.keyType.Yql())
- buffer.WriteByte(',')
- buffer.WriteString(v.valueType.Yql())
- buffer.WriteByte('>')
- return buffer.String()
-}
-
-func (v *dictType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(*dictType)
- if !ok {
- return false
- }
- if !v.keyType.equalsTo(vv.keyType) {
- return false
- }
- if !v.valueType.equalsTo(vv.valueType) {
- return false
- }
- return true
-}
-
-func (v *dictType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- typeDict := a.TypeDict()
-
- typeDict.DictType = a.Dict()
-
- typeDict.DictType.Key = v.keyType.toYDB(a)
- typeDict.DictType.Payload = v.valueType.toYDB(a)
-
- t.Type = typeDict
-
- return t
-}
-
-func Dict(key, value Type) (v *dictType) {
- return &dictType{
- keyType: key,
- valueType: value,
- }
-}
-
-type emptyListType struct{}
-
-func (v emptyListType) Yql() string {
- return "EmptyList"
-}
-
-func (v emptyListType) String() string {
- return v.Yql()
-}
-
-func (emptyListType) equalsTo(rhs Type) bool {
- _, ok := rhs.(emptyListType)
- return ok
-}
-
-func (emptyListType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- t.Type = a.TypeEmptyList()
-
- return t
-}
-
-func EmptyList() emptyListType {
- return emptyListType{}
-}
-
-type emptyDictType struct{}
-
-func (v emptyDictType) String() string {
- return v.Yql()
-}
-
-func (v emptyDictType) Yql() string {
- return "EmptyDict"
-}
-
-func (emptyDictType) equalsTo(rhs Type) bool {
- _, ok := rhs.(emptyDictType)
- return ok
-}
-
-func (emptyDictType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- t.Type = a.TypeEmptyDict()
-
- return t
-}
-
-func EmptySet() emptyDictType {
- return emptyDictType{}
-}
-
-func EmptyDict() emptyDictType {
- return emptyDictType{}
-}
-
-type listType struct {
- itemType Type
-}
-
-func (v *listType) String() string {
- return v.Yql()
-}
-
-func (v *listType) Yql() string {
- return "List<" + v.itemType.Yql() + ">"
-}
-
-func (v *listType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(*listType)
- if !ok {
- return false
- }
- return v.itemType.equalsTo(vv.itemType)
-}
-
-func (v *listType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- list := a.List()
-
- list.Item = v.itemType.toYDB(a)
-
- typeList := a.TypeList()
- typeList.ListType = list
-
- t.Type = typeList
-
- return t
-}
-
-func List(t Type) *listType {
- return &listType{
- itemType: t,
- }
-}
-
-type setType struct {
- itemType Type
-}
-
-func (v *setType) String() string {
- return v.Yql()
-}
-
-func (v *setType) Yql() string {
- return "Set<" + v.itemType.Yql() + ">"
-}
-
-func (v *setType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(*setType)
- if !ok {
- return false
- }
- return v.itemType.equalsTo(vv.itemType)
-}
-
-func (v *setType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- typeDict := a.TypeDict()
-
- typeDict.DictType = a.Dict()
-
- typeDict.DictType.Key = v.itemType.toYDB(a)
- typeDict.DictType.Payload = _voidType
-
- t.Type = typeDict
-
- return t
-}
-
-func Set(t Type) *setType {
- return &setType{
- itemType: t,
- }
-}
-
-type optionalType struct {
- innerType Type
-}
-
-func (v optionalType) IsOptional() {}
-
-func (v optionalType) InnerType() Type {
- return v.innerType
-}
-
-func (v optionalType) String() string {
- return v.Yql()
-}
-
-func (v optionalType) Yql() string {
- return "Optional<" + v.innerType.Yql() + ">"
-}
-
-func (v optionalType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(optionalType)
- if !ok {
- return false
- }
- return v.innerType.equalsTo(vv.innerType)
-}
-
-func (v optionalType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- typeOptional := a.TypeOptional()
-
- typeOptional.OptionalType = a.Optional()
-
- typeOptional.OptionalType.Item = v.innerType.toYDB(a)
-
- t.Type = typeOptional
-
- return t
-}
-
-func Optional(t Type) optionalType {
- return optionalType{
- innerType: t,
- }
-}
-
-type PrimitiveType uint
-
-func (v PrimitiveType) String() string {
- return v.Yql()
-}
-
-func (v PrimitiveType) Yql() string {
- return primitiveString[v]
-}
-
-const (
- TypeUnknown PrimitiveType = iota
- TypeBool
- TypeInt8
- TypeUint8
- TypeInt16
- TypeUint16
- TypeInt32
- TypeUint32
- TypeInt64
- TypeUint64
- TypeFloat
- TypeDouble
- TypeDate
- TypeDatetime
- TypeTimestamp
- TypeInterval
- TypeTzDate
- TypeTzDatetime
- TypeTzTimestamp
- TypeBytes
- TypeText
- TypeYSON
- TypeJSON
- TypeUUID
- TypeJSONDocument
- TypeDyNumber
-)
-
-var primitive = [...]*Ydb.Type{
- TypeBool: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL}},
- TypeInt8: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8}},
- TypeUint8: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8}},
- TypeInt16: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16}},
- TypeUint16: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16}},
- TypeInt32: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32}},
- TypeUint32: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32}},
- TypeInt64: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64}},
- TypeUint64: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64}},
- TypeFloat: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT}},
- TypeDouble: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE}},
- TypeDate: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE}},
- TypeDatetime: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME}},
- TypeTimestamp: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP}},
- TypeInterval: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL}},
- TypeTzDate: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE}},
- TypeTzDatetime: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME}},
- TypeTzTimestamp: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP}},
- TypeBytes: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING}},
- TypeText: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8}},
- TypeYSON: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON}},
- TypeJSON: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON}},
- TypeUUID: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID}},
- TypeJSONDocument: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT}},
- TypeDyNumber: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DYNUMBER}},
-}
-
-var primitiveString = [...]string{
- TypeUnknown: "",
- TypeBool: "Bool",
- TypeInt8: "Int8",
- TypeUint8: "Uint8",
- TypeInt16: "Int16",
- TypeUint16: "Uint16",
- TypeInt32: "Int32",
- TypeUint32: "Uint32",
- TypeInt64: "Int64",
- TypeUint64: "Uint64",
- TypeFloat: "Float",
- TypeDouble: "Double",
- TypeDate: "Date",
- TypeDatetime: "Datetime",
- TypeTimestamp: "Timestamp",
- TypeInterval: "Interval",
- TypeTzDate: "TzDate",
- TypeTzDatetime: "TzDatetime",
- TypeTzTimestamp: "TzTimestamp",
- TypeBytes: "String",
- TypeText: "Utf8",
- TypeYSON: "Yson",
- TypeJSON: "Json",
- TypeUUID: "Uuid",
- TypeJSONDocument: "JsonDocument",
- TypeDyNumber: "DyNumber",
-}
-
-func (v PrimitiveType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(PrimitiveType)
- if !ok {
- return false
- }
- return v == vv
-}
-
-func (v PrimitiveType) toYDB(*allocator.Allocator) *Ydb.Type {
- return primitive[v]
-}
-
-type (
- StructField struct {
- Name string
- T Type
- }
- StructType struct {
- fields []StructField
- }
-)
-
-func (v *StructType) String() string {
- return v.Yql()
-}
-
-func (v *StructType) Yql() string {
- buffer := xstring.Buffer()
- defer buffer.Free()
- buffer.WriteString("Struct<")
- for i := range v.fields {
- if i > 0 {
- buffer.WriteByte(',')
- }
- buffer.WriteString("'" + v.fields[i].Name + "'")
- buffer.WriteByte(':')
- buffer.WriteString(v.fields[i].T.Yql())
- }
- buffer.WriteByte('>')
- return buffer.String()
-}
-
-func (v *StructType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(*StructType)
- if !ok {
- return false
- }
- if len(v.fields) != len(vv.fields) {
- return false
- }
- for i := range v.fields {
- if v.fields[i].Name != vv.fields[i].Name {
- return false
- }
- if !v.fields[i].T.equalsTo(vv.fields[i].T) {
- return false
- }
- }
- return true
-}
-
-func (v *StructType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- typeStruct := a.TypeStruct()
-
- typeStruct.StructType = a.Struct()
-
- for i := range v.fields {
- structMember := a.StructMember()
- structMember.Name = v.fields[i].Name
- structMember.Type = v.fields[i].T.toYDB(a)
- typeStruct.StructType.Members = append(
- typeStruct.StructType.Members,
- structMember,
- )
- }
-
- t.Type = typeStruct
-
- return t
-}
-
-func Struct(fields ...StructField) (v *StructType) {
- return &StructType{
- fields: fields,
- }
-}
-
-func StructFields(ms []*Ydb.StructMember) []StructField {
- fs := make([]StructField, len(ms))
- for i, m := range ms {
- fs[i] = StructField{
- Name: m.Name,
- T: TypeFromYDB(m.Type),
- }
- }
- return fs
-}
-
-type TupleType struct {
- items []Type
-}
-
-func (v *TupleType) String() string {
- return v.Yql()
-}
-
-func (v *TupleType) Yql() string {
- buffer := xstring.Buffer()
- defer buffer.Free()
- buffer.WriteString("Tuple<")
- for i, t := range v.items {
- if i > 0 {
- buffer.WriteByte(',')
- }
- buffer.WriteString(t.Yql())
- }
- buffer.WriteByte('>')
- return buffer.String()
-}
-
-func (v *TupleType) equalsTo(rhs Type) bool {
- vv, ok := rhs.(*TupleType)
- if !ok {
- return false
- }
- if len(v.items) != len(vv.items) {
- return false
- }
- for i := range v.items {
- if !v.items[i].equalsTo(vv.items[i]) {
- return false
- }
- }
- return true
-}
-
-func (v *TupleType) toYDB(a *allocator.Allocator) *Ydb.Type {
- var items []Type
- if v != nil {
- items = v.items
- }
- t := a.Type()
-
- typeTuple := a.TypeTuple()
-
- typeTuple.TupleType = a.Tuple()
-
- for _, vv := range items {
- typeTuple.TupleType.Elements = append(typeTuple.TupleType.Elements, vv.toYDB(a))
- }
-
- t.Type = typeTuple
-
- return t
-}
-
-func Tuple(items ...Type) (v *TupleType) {
- return &TupleType{
- items: items,
- }
-}
-
-type variantStructType struct {
- *StructType
-}
-
-func (v *variantStructType) Yql() string {
- buffer := xstring.Buffer()
- defer buffer.Free()
- buffer.WriteString("Variant<")
- for i := range v.fields {
- if i > 0 {
- buffer.WriteByte(',')
- }
- buffer.WriteString("'" + v.fields[i].Name + "'")
- buffer.WriteByte(':')
- buffer.WriteString(v.fields[i].T.Yql())
- }
- buffer.WriteByte('>')
- return buffer.String()
-}
-
-func (v *variantStructType) equalsTo(rhs Type) bool {
- switch t := rhs.(type) {
- case *variantStructType:
- return v.StructType.equalsTo(t.StructType)
- case *StructType:
- return v.StructType.equalsTo(t)
- default:
- return false
- }
-}
-
-func (v *variantStructType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- typeVariant := a.TypeVariant()
-
- typeVariant.VariantType = a.Variant()
-
- structItems := a.VariantStructItems()
- structItems.StructItems = v.StructType.toYDB(a).Type.(*Ydb.Type_StructType).StructType
-
- typeVariant.VariantType.Type = structItems
-
- t.Type = typeVariant
-
- return t
-}
-
-func VariantStruct(fields ...StructField) *variantStructType {
- return &variantStructType{
- StructType: Struct(fields...),
- }
-}
-
-type variantTupleType struct {
- *TupleType
-}
-
-func (v *variantTupleType) Yql() string {
- buffer := xstring.Buffer()
- defer buffer.Free()
- buffer.WriteString("Variant<")
- for i, t := range v.items {
- if i > 0 {
- buffer.WriteByte(',')
- }
- buffer.WriteString(t.Yql())
- }
- buffer.WriteByte('>')
- return buffer.String()
-}
-
-func (v *variantTupleType) equalsTo(rhs Type) bool {
- switch t := rhs.(type) {
- case *variantTupleType:
- return v.TupleType.equalsTo(t.TupleType)
- case *TupleType:
- return v.TupleType.equalsTo(t)
- default:
- return false
- }
-}
-
-func (v *variantTupleType) toYDB(a *allocator.Allocator) *Ydb.Type {
- t := a.Type()
-
- typeVariant := a.TypeVariant()
-
- typeVariant.VariantType = a.Variant()
-
- tupleItems := a.VariantTupleItems()
- tupleItems.TupleItems = v.TupleType.toYDB(a).Type.(*Ydb.Type_TupleType).TupleType
-
- typeVariant.VariantType.Type = tupleItems
-
- t.Type = typeVariant
-
- return t
-}
-
-func VariantTuple(items ...Type) *variantTupleType {
- return &variantTupleType{
- TupleType: Tuple(items...),
- }
-}
-
-type voidType struct{}
-
-func (v voidType) String() string {
- return v.Yql()
-}
-
-func (v voidType) Yql() string {
- return "Void"
-}
-
-var _voidType = &Ydb.Type{
- Type: &Ydb.Type_VoidType{},
-}
-
-func (v voidType) equalsTo(rhs Type) bool {
- _, ok := rhs.(voidType)
- return ok
-}
-
-func (voidType) toYDB(*allocator.Allocator) *Ydb.Type {
- return _voidType
-}
-
-func Void() voidType {
- return voidType{}
-}
-
-type nullType struct{}
-
-func (v nullType) String() string {
- return v.Yql()
-}
-
-func (v nullType) Yql() string {
- return "Null"
-}
-
-var _nullType = &Ydb.Type{
- Type: &Ydb.Type_NullType{},
-}
-
-func (v nullType) equalsTo(rhs Type) bool {
- _, ok := rhs.(nullType)
- return ok
-}
-
-func (nullType) toYDB(*allocator.Allocator) *Ydb.Type {
- return _nullType
-}
-
-func Null() nullType {
- return nullType{}
-}
diff --git a/internal/value/type_test.go b/internal/value/type_test.go
deleted file mode 100644
index 22236684e..000000000
--- a/internal/value/type_test.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package value
-
-import (
- "testing"
-)
-
-func TestTypeToString(t *testing.T) {
- for _, tt := range []struct {
- t Type
- s string
- }{
- {
- t: Void(),
- s: "Void",
- },
- {
- t: Null(),
- s: "Null",
- },
- {
- t: TypeBool,
- s: "Bool",
- },
- {
- t: TypeInt8,
- s: "Int8",
- },
- {
- t: TypeUint8,
- s: "Uint8",
- },
- {
- t: TypeInt16,
- s: "Int16",
- },
- {
- t: TypeUint16,
- s: "Uint16",
- },
- {
- t: TypeInt32,
- s: "Int32",
- },
- {
- t: TypeUint32,
- s: "Uint32",
- },
- {
- t: TypeInt64,
- s: "Int64",
- },
- {
- t: TypeUint64,
- s: "Uint64",
- },
- {
- t: TypeFloat,
- s: "Float",
- },
- {
- t: TypeDouble,
- s: "Double",
- },
- {
- t: TypeDate,
- s: "Date",
- },
- {
- t: TypeDatetime,
- s: "Datetime",
- },
- {
- t: TypeTimestamp,
- s: "Timestamp",
- },
- {
- t: TypeInterval,
- s: "Interval",
- },
- {
- t: TypeTzDate,
- s: "TzDate",
- },
- {
- t: TypeTzDatetime,
- s: "TzDatetime",
- },
- {
- t: TypeTzTimestamp,
- s: "TzTimestamp",
- },
- {
- t: TypeBytes,
- s: "String",
- },
- {
- t: TypeText,
- s: "Utf8",
- },
- {
- t: TypeYSON,
- s: "Yson",
- },
- {
- t: TypeJSON,
- s: "Json",
- },
- {
- t: TypeUUID,
- s: "Uuid",
- },
- {
- t: TypeJSONDocument,
- s: "JsonDocument",
- },
- {
- t: TypeDyNumber,
- s: "DyNumber",
- },
- {
- t: Optional(TypeBool),
- s: "Optional",
- },
- {
- t: Optional(TypeInt8),
- s: "Optional",
- },
- {
- t: Optional(TypeUint8),
- s: "Optional",
- },
- {
- t: Optional(TypeInt16),
- s: "Optional",
- },
- {
- t: Optional(TypeUint16),
- s: "Optional",
- },
- {
- t: Optional(TypeInt32),
- s: "Optional",
- },
- {
- t: Optional(TypeUint32),
- s: "Optional",
- },
- {
- t: Optional(TypeInt64),
- s: "Optional",
- },
- {
- t: Optional(TypeUint64),
- s: "Optional",
- },
- {
- t: Optional(TypeFloat),
- s: "Optional",
- },
- {
- t: Optional(TypeDouble),
- s: "Optional",
- },
- {
- t: Optional(TypeDate),
- s: "Optional",
- },
- {
- t: Optional(TypeDatetime),
- s: "Optional",
- },
- {
- t: Optional(TypeTimestamp),
- s: "Optional",
- },
- {
- t: Optional(TypeInterval),
- s: "Optional",
- },
- {
- t: Optional(TypeTzDate),
- s: "Optional",
- },
- {
- t: Optional(TypeTzDatetime),
- s: "Optional",
- },
- {
- t: Optional(TypeTzTimestamp),
- s: "Optional",
- },
- {
- t: Optional(TypeBytes),
- s: "Optional",
- },
- {
- t: Optional(TypeText),
- s: "Optional",
- },
- {
- t: Optional(TypeYSON),
- s: "Optional",
- },
- {
- t: Optional(TypeJSON),
- s: "Optional",
- },
- {
- t: Optional(TypeUUID),
- s: "Optional",
- },
- {
- t: Optional(TypeJSONDocument),
- s: "Optional",
- },
- {
- t: Optional(TypeDyNumber),
- s: "Optional",
- },
- {
- t: Decimal(22, 9),
- s: "Decimal(22,9)",
- },
- {
- t: Dict(TypeText, TypeTimestamp),
- s: "Dict",
- },
- {
- t: EmptyList(),
- s: "EmptyList",
- },
- {
- t: List(TypeUint32),
- s: "List",
- },
- {
- t: Set(TypeUint32),
- s: "Set",
- },
- {
- t: EmptySet(),
- s: "EmptyDict",
- },
- {
- t: EmptyDict(),
- s: "EmptyDict",
- },
- {
- t: VariantStruct(
- StructField{
- Name: "a",
- T: TypeBool,
- },
- StructField{
- Name: "b",
- T: TypeFloat,
- },
- ),
- s: "Variant<'a':Bool,'b':Float>",
- },
- {
- t: VariantTuple(
- TypeBool,
- TypeFloat,
- ),
- s: "Variant",
- },
- } {
- t.Run(tt.s, func(t *testing.T) {
- if got := tt.t.Yql(); got != tt.s {
- t.Errorf("s representations not equals:\n\n - got: %s\n\n - want: %s", got, tt.s)
- }
- })
- }
-}
diff --git a/internal/value/value.go b/internal/value/value.go
index cd8b2079e..14a8b43f7 100644
--- a/internal/value/value.go
+++ b/internal/value/value.go
@@ -2,9 +2,9 @@ package value
import (
"encoding/binary"
- "errors"
"fmt"
"math/big"
+ "reflect"
"sort"
"strconv"
"time"
@@ -14,12 +14,13 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/decimal"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
)
type Value interface {
- Type() Type
+ Type() types.Type
Yql() string
castTo(dst interface{}) error
@@ -29,7 +30,7 @@ type Value interface {
func ToYDB(v Value, a *allocator.Allocator) *Ydb.TypedValue {
tv := a.TypedValue()
- tv.Type = v.Type().toYDB(a)
+ tv.Type = v.Type().ToYDB(a)
tv.Value = v.toYDB(a)
return tv
@@ -39,6 +40,7 @@ func ToYDB(v Value, a *allocator.Allocator) *Ydb.TypedValue {
func BigEndianUint128(hi, lo uint64) (v [16]byte) {
binary.BigEndian.PutUint64(v[0:8], hi)
binary.BigEndian.PutUint64(v[8:16], lo)
+
return v
}
@@ -47,19 +49,20 @@ func FromYDB(t *Ydb.Type, v *Ydb.Value) Value {
if err != nil {
panic(err)
}
+
return vv
}
-func nullValueFromYDB(x *Ydb.Value, t Type) (_ Value, ok bool) {
+func nullValueFromYDB(x *Ydb.Value, t types.Type) (_ Value, ok bool) {
for {
- switch xx := x.Value.(type) {
+ switch xx := x.GetValue().(type) {
case *Ydb.Value_NestedValue:
x = xx.NestedValue
case *Ydb.Value_NullFlagValue:
switch tt := t.(type) {
- case optionalType:
- return NullValue(tt.innerType), true
- case voidType:
+ case types.Optional:
+ return NullValue(tt.InnerType()), true
+ case types.Void:
return VoidValue(), true
default:
return nil, false
@@ -70,57 +73,57 @@ func nullValueFromYDB(x *Ydb.Value, t Type) (_ Value, ok bool) {
}
}
-func primitiveValueFromYDB(t PrimitiveType, v *Ydb.Value) (Value, error) {
+func primitiveValueFromYDB(t types.Primitive, v *Ydb.Value) (Value, error) {
switch t {
- case TypeBool:
+ case types.Bool:
return BoolValue(v.GetBoolValue()), nil
- case TypeInt8:
+ case types.Int8:
return Int8Value(int8(v.GetInt32Value())), nil
- case TypeInt16:
+ case types.Int16:
return Int16Value(int16(v.GetInt32Value())), nil
- case TypeInt32:
+ case types.Int32:
return Int32Value(v.GetInt32Value()), nil
- case TypeInt64:
+ case types.Int64:
return Int64Value(v.GetInt64Value()), nil
- case TypeUint8:
+ case types.Uint8:
return Uint8Value(uint8(v.GetUint32Value())), nil
- case TypeUint16:
+ case types.Uint16:
return Uint16Value(uint16(v.GetUint32Value())), nil
- case TypeUint32:
+ case types.Uint32:
return Uint32Value(v.GetUint32Value()), nil
- case TypeUint64:
+ case types.Uint64:
return Uint64Value(v.GetUint64Value()), nil
- case TypeDate:
+ case types.Date:
return DateValue(v.GetUint32Value()), nil
- case TypeDatetime:
+ case types.Datetime:
return DatetimeValue(v.GetUint32Value()), nil
- case TypeInterval:
+ case types.Interval:
return IntervalValue(v.GetInt64Value()), nil
- case TypeTimestamp:
+ case types.Timestamp:
return TimestampValue(v.GetUint64Value()), nil
- case TypeFloat:
+ case types.Float:
return FloatValue(v.GetFloatValue()), nil
- case TypeDouble:
+ case types.Double:
return DoubleValue(v.GetDoubleValue()), nil
- case TypeText:
+ case types.Text:
return TextValue(v.GetTextValue()), nil
- case TypeYSON:
+ case types.YSON:
switch vv := v.GetValue().(type) {
case *Ydb.Value_TextValue:
return YSONValue(xstring.ToBytes(vv.TextValue)), nil
@@ -130,29 +133,29 @@ func primitiveValueFromYDB(t PrimitiveType, v *Ydb.Value) (Value, error) {
return nil, xerrors.WithStackTrace(fmt.Errorf("uncovered YSON internal type: %T", vv))
}
- case TypeJSON:
+ case types.JSON:
return JSONValue(v.GetTextValue()), nil
- case TypeJSONDocument:
+ case types.JSONDocument:
return JSONDocumentValue(v.GetTextValue()), nil
- case TypeDyNumber:
+ case types.DyNumber:
return DyNumberValue(v.GetTextValue()), nil
- case TypeTzDate:
+ case types.TzDate:
return TzDateValue(v.GetTextValue()), nil
- case TypeTzDatetime:
+ case types.TzDatetime:
return TzDatetimeValue(v.GetTextValue()), nil
- case TypeTzTimestamp:
+ case types.TzTimestamp:
return TzTimestampValue(v.GetTextValue()), nil
- case TypeBytes:
+ case types.Bytes:
return BytesValue(v.GetBytesValue()), nil
- case TypeUUID:
- return UUIDValue(BigEndianUint128(v.High_128, v.GetLow_128())), nil
+ case types.UUID:
+ return UUIDValue(BigEndianUint128(v.GetHigh_128(), v.GetLow_128())), nil
default:
return nil, xerrors.WithStackTrace(fmt.Errorf("uncovered primitive type: %T", t))
@@ -160,117 +163,133 @@ func primitiveValueFromYDB(t PrimitiveType, v *Ydb.Value) (Value, error) {
}
func fromYDB(t *Ydb.Type, v *Ydb.Value) (Value, error) {
- tt := TypeFromYDB(t)
+ tt := types.TypeFromYDB(t)
if vv, ok := nullValueFromYDB(v, tt); ok {
return vv, nil
}
switch ttt := tt.(type) {
- case PrimitiveType:
+ case types.Primitive:
return primitiveValueFromYDB(ttt, v)
- case voidType:
+ case types.Void:
return VoidValue(), nil
- case nullType:
+ case types.Null:
return NullValue(tt), nil
- case *DecimalType:
- return DecimalValue(BigEndianUint128(v.High_128, v.GetLow_128()), ttt.Precision, ttt.Scale), nil
+ case *types.Decimal:
+ return DecimalValue(BigEndianUint128(v.GetHigh_128(), v.GetLow_128()), ttt.Precision(), ttt.Scale()), nil
- case optionalType:
- t = t.Type.(*Ydb.Type_OptionalType).OptionalType.Item
- if nestedValue, ok := v.Value.(*Ydb.Value_NestedValue); ok {
+ case types.Optional:
+ t = t.GetType().(*Ydb.Type_OptionalType).OptionalType.GetItem()
+ if nestedValue, ok := v.GetValue().(*Ydb.Value_NestedValue); ok {
return OptionalValue(FromYDB(t, nestedValue.NestedValue)), nil
}
+
return OptionalValue(FromYDB(t, v)), nil
- case *listType:
+ case *types.List:
return ListValue(func() []Value {
vv := make([]Value, len(v.GetItems()))
a := allocator.New()
defer a.Free()
for i, vvv := range v.GetItems() {
- vv[i] = FromYDB(ttt.itemType.toYDB(a), vvv)
+ vv[i] = FromYDB(ttt.ItemType().ToYDB(a), vvv)
}
+
return vv
}()...), nil
- case *TupleType:
+ case *types.Tuple:
return TupleValue(func() []Value {
vv := make([]Value, len(v.GetItems()))
a := allocator.New()
defer a.Free()
for i, vvv := range v.GetItems() {
- vv[i] = FromYDB(ttt.items[i].toYDB(a), vvv)
+ vv[i] = FromYDB(ttt.ItemType(i).ToYDB(a), vvv)
}
+
return vv
}()...), nil
- case *StructType:
+ case *types.Struct:
return StructValue(func() []StructValueField {
vv := make([]StructValueField, len(v.GetItems()))
a := allocator.New()
defer a.Free()
for i, vvv := range v.GetItems() {
vv[i] = StructValueField{
- Name: ttt.fields[i].Name,
- V: FromYDB(ttt.fields[i].T.toYDB(a), vvv),
+ Name: ttt.Field(i).Name,
+ V: FromYDB(ttt.Field(i).T.ToYDB(a), vvv),
}
}
+
return vv
}()...), nil
- case *dictType:
+ case *types.Dict:
return DictValue(func() []DictValueField {
vv := make([]DictValueField, len(v.GetPairs()))
a := allocator.New()
defer a.Free()
for i, vvv := range v.GetPairs() {
vv[i] = DictValueField{
- K: FromYDB(ttt.keyType.toYDB(a), vvv.Key),
- V: FromYDB(ttt.valueType.toYDB(a), vvv.Payload),
+ K: FromYDB(ttt.KeyType().ToYDB(a), vvv.GetKey()),
+ V: FromYDB(ttt.ValueType().ToYDB(a), vvv.GetPayload()),
}
}
+
return vv
}()...), nil
- case *setType:
+ case *types.Set:
return SetValue(func() []Value {
vv := make([]Value, len(v.GetPairs()))
a := allocator.New()
defer a.Free()
for i, vvv := range v.GetPairs() {
- vv[i] = FromYDB(ttt.itemType.toYDB(a), vvv.Key)
+ vv[i] = FromYDB(ttt.ItemType().ToYDB(a), vvv.GetKey())
}
+
return vv
}()...), nil
- case *variantStructType:
+ case *types.VariantStruct:
a := allocator.New()
defer a.Free()
+
return VariantValueStruct(
FromYDB(
- ttt.StructType.fields[v.VariantIndex].T.toYDB(a),
- v.Value.(*Ydb.Value_NestedValue).NestedValue,
+ ttt.Struct.Field(int(v.GetVariantIndex())).T.ToYDB(a),
+ v.GetValue().(*Ydb.Value_NestedValue).NestedValue,
),
- ttt.StructType.fields[v.VariantIndex].Name,
- ttt.StructType,
+ ttt.Struct.Field(int(v.GetVariantIndex())).Name,
+ ttt.Struct,
), nil
- case *variantTupleType:
+ case *types.VariantTuple:
a := allocator.New()
defer a.Free()
+
return VariantValueTuple(
FromYDB(
- ttt.TupleType.items[v.VariantIndex].toYDB(a),
- v.Value.(*Ydb.Value_NestedValue).NestedValue,
+ ttt.Tuple.ItemType(int(v.GetVariantIndex())).ToYDB(a),
+ v.GetValue().(*Ydb.Value_NestedValue).NestedValue,
),
- v.VariantIndex,
- ttt.TupleType,
+ v.GetVariantIndex(),
+ ttt.Tuple,
), nil
+ case *types.PgType:
+ return &pgValue{
+ t: types.PgType{
+ OID: ttt.OID,
+ },
+ val: v.GetTextValue(),
+ }, nil
+
default:
return nil, xerrors.WithStackTrace(fmt.Errorf("uncovered type: %T", ttt))
}
@@ -282,12 +301,17 @@ func (v boolValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *bool:
*vv = bool(v)
+
return nil
case *string:
*vv = strconv.FormatBool(bool(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -295,8 +319,8 @@ func (v boolValue) Yql() string {
return strconv.FormatBool(bool(v))
}
-func (boolValue) Type() Type {
- return TypeBool
+func (boolValue) Type() types.Type {
+ return types.Bool
}
func (v boolValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -320,18 +344,25 @@ func (v dateValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *time.Time:
*vv = DateToTime(uint32(v))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *int32:
*vv = int32(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -339,8 +370,8 @@ func (v dateValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), DateToTime(uint32(v)).UTC().Format(LayoutDate))
}
-func (dateValue) Type() Type {
- return TypeDate
+func (dateValue) Type() types.Type {
+ return types.Date
}
func (v dateValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -369,18 +400,25 @@ func (v datetimeValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *time.Time:
*vv = DatetimeToTime(uint32(v))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *uint32:
*vv = uint32(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -388,8 +426,8 @@ func (v datetimeValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), DatetimeToTime(uint32(v)).UTC().Format(LayoutDatetime))
}
-func (datetimeValue) Type() Type {
- return TypeDatetime
+func (datetimeValue) Type() types.Type {
+ return types.Datetime
}
func (v datetimeValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -415,7 +453,7 @@ var _ DecimalValuer = (*decimalValue)(nil)
type decimalValue struct {
value [16]byte
- innerType *DecimalType
+ innerType *types.Decimal
}
func (v *decimalValue) Value() [16]byte {
@@ -423,11 +461,11 @@ func (v *decimalValue) Value() [16]byte {
}
func (v *decimalValue) Precision() uint32 {
- return v.innerType.Precision
+ return v.innerType.Precision()
}
func (v *decimalValue) Scale() uint32 {
- return v.innerType.Scale
+ return v.innerType.Scale()
}
type DecimalValuer interface {
@@ -437,7 +475,10 @@ type DecimalValuer interface {
}
func (v *decimalValue) castTo(dst interface{}) error {
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' to '%T' destination", v, dst))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' to '%T' destination",
+ ErrCannotCast, v, dst,
+ ))
}
func (v *decimalValue) Yql() string {
@@ -446,18 +487,19 @@ func (v *decimalValue) Yql() string {
buffer.WriteString(v.innerType.Name())
buffer.WriteByte('(')
buffer.WriteByte('"')
- s := decimal.FromBytes(v.value[:], v.innerType.Precision, v.innerType.Scale).String()
- buffer.WriteString(s[:len(s)-int(v.innerType.Scale)] + "." + s[len(s)-int(v.innerType.Scale):])
+ s := decimal.FromBytes(v.value[:], v.innerType.Precision(), v.innerType.Scale()).String()
+ buffer.WriteString(s[:len(s)-int(v.innerType.Scale())] + "." + s[len(s)-int(v.innerType.Scale()):])
buffer.WriteByte('"')
buffer.WriteByte(',')
- buffer.WriteString(strconv.FormatUint(uint64(v.innerType.Precision), 10))
+ buffer.WriteString(strconv.FormatUint(uint64(v.innerType.Precision()), 10))
buffer.WriteByte(',')
- buffer.WriteString(strconv.FormatUint(uint64(v.innerType.Scale), 10))
+ buffer.WriteString(strconv.FormatUint(uint64(v.innerType.Scale()), 10))
buffer.WriteByte(')')
+
return buffer.String()
}
-func (v *decimalValue) Type() Type {
+func (v *decimalValue) Type() types.Type {
return v.innerType
}
@@ -478,16 +520,17 @@ func (v *decimalValue) toYDB(a *allocator.Allocator) *Ydb.Value {
func DecimalValueFromBigInt(v *big.Int, precision, scale uint32) *decimalValue {
b := decimal.BigIntToByte(v, precision, scale)
+
return DecimalValue(b, precision, scale)
}
func DecimalValue(v [16]byte, precision, scale uint32) *decimalValue {
return &decimalValue{
value: v,
- innerType: &DecimalType{
- Precision: precision,
- Scale: scale,
- },
+ innerType: types.NewDecimal(
+ precision,
+ scale,
+ ),
}
}
@@ -497,7 +540,7 @@ type (
V Value
}
dictValue struct {
- t Type
+ t types.Type
values []DictValueField
}
)
@@ -507,11 +550,15 @@ func (v *dictValue) DictValues() map[Value]Value {
for i := range v.values {
values[v.values[i].K] = v.values[i].V
}
+
return values
}
func (v *dictValue) castTo(dst interface{}) error {
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' to '%T' destination", v, dst))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' to '%T' destination",
+ ErrCannotCast, v, dst,
+ ))
}
func (v *dictValue) Yql() string {
@@ -527,10 +574,11 @@ func (v *dictValue) Yql() string {
buffer.WriteString(v.values[i].V.Yql())
}
buffer.WriteByte('}')
+
return buffer.String()
}
-func (v *dictValue) Type() Type {
+func (v *dictValue) Type() types.Type {
return v.t
}
@@ -547,7 +595,7 @@ func (v *dictValue) toYDB(a *allocator.Allocator) *Ydb.Value {
pair.Key = values[i].K.toYDB(a)
pair.Payload = values[i].V.toYDB(a)
- vvv.Pairs = append(vvv.Pairs, pair)
+ vvv.Pairs = append(vvv.GetPairs(), pair)
}
return vvv
@@ -557,13 +605,14 @@ func DictValue(values ...DictValueField) *dictValue {
sort.Slice(values, func(i, j int) bool {
return values[i].K.Yql() < values[j].K.Yql()
})
- var t Type
+ var t types.Type
switch {
case len(values) > 0:
- t = Dict(values[0].K.Type(), values[0].V.Type())
+ t = types.NewDict(values[0].K.Type(), values[0].V.Type())
default:
- t = EmptyDict()
+ t = types.NewEmptyDict()
}
+
return &dictValue{
t: t,
values: values,
@@ -578,15 +627,21 @@ func (v *doubleValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatFloat(v.value, 'f', -1, 64)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatFloat(v.value, 'f', -1, 64))
+
return nil
case *float64:
*vv = v.value
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -594,8 +649,8 @@ func (v *doubleValue) Yql() string {
return fmt.Sprintf("%s(\"%v\")", v.Type().Yql(), v.value)
}
-func (*doubleValue) Type() Type {
- return TypeDouble
+func (*doubleValue) Type() types.Type {
+ return types.Double
}
func (v *doubleValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -620,12 +675,17 @@ func (v dyNumberValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -633,8 +693,8 @@ func (v dyNumberValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), string(v))
}
-func (dyNumberValue) Type() Type {
- return TypeDyNumber
+func (dyNumberValue) Type() types.Type {
+ return types.DyNumber
}
func (v dyNumberValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -659,18 +719,25 @@ func (v *floatValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatFloat(float64(v.value), 'f', -1, 32)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatFloat(float64(v.value), 'f', -1, 32))
+
return nil
case *float64:
*vv = float64(v.value)
+
return nil
case *float32:
*vv = v.value
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -678,8 +745,8 @@ func (v *floatValue) Yql() string {
return fmt.Sprintf("%s(\"%v\")", v.Type().Yql(), v.value)
}
-func (*floatValue) Type() Type {
- return TypeFloat
+func (*floatValue) Type() types.Type {
+ return types.Float
}
func (v *floatValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -704,30 +771,41 @@ func (v int8Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *int32:
*vv = int32(v)
+
return nil
case *int16:
*vv = int16(v)
+
return nil
case *int8:
*vv = int8(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
case *float32:
*vv = float32(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -735,8 +813,8 @@ func (v int8Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "t"
}
-func (int8Value) Type() Type {
- return TypeInt8
+func (int8Value) Type() types.Type {
+ return types.Int8
}
func (v int8Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -759,27 +837,37 @@ func (v int16Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *int32:
*vv = int32(v)
+
return nil
case *int16:
*vv = int16(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
case *float32:
*vv = float32(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -787,8 +875,8 @@ func (v int16Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "s"
}
-func (int16Value) Type() Type {
- return TypeInt16
+func (int16Value) Type() types.Type {
+ return types.Int16
}
func (v int16Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -811,27 +899,37 @@ func (v int32Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *int:
*vv = int(v)
+
return nil
case *int32:
*vv = int32(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
case *float32:
*vv = float32(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -839,8 +937,8 @@ func (v int32Value) Yql() string {
return strconv.FormatInt(int64(v), 10)
}
-func (int32Value) Type() Type {
- return TypeInt32
+func (int32Value) Type() types.Type {
+ return types.Int32
}
func (v int32Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -863,18 +961,25 @@ func (v int64Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -882,8 +987,8 @@ func (v int64Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "l"
}
-func (int64Value) Type() Type {
- return TypeInt64
+func (int64Value) Type() types.Type {
+ return types.Int64
}
func (v int64Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -906,12 +1011,17 @@ func (v intervalValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *time.Duration:
*vv = IntervalToDuration(int64(v))
+
return nil
case *int64:
*vv = int64(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -952,11 +1062,12 @@ func (v intervalValue) Yql() string {
}
buffer.WriteByte('"')
buffer.WriteByte(')')
+
return buffer.String()
}
-func (intervalValue) Type() Type {
- return TypeInterval
+func (intervalValue) Type() types.Type {
+ return types.Interval
}
func (v intervalValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -984,12 +1095,17 @@ func (v jsonValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -997,8 +1113,8 @@ func (v jsonValue) Yql() string {
return fmt.Sprintf("%s(@@%s@@)", v.Type().Yql(), string(v))
}
-func (jsonValue) Type() Type {
- return TypeJSON
+func (jsonValue) Type() types.Type {
+ return types.JSON
}
func (v jsonValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1021,12 +1137,17 @@ func (v jsonDocumentValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1034,8 +1155,8 @@ func (v jsonDocumentValue) Yql() string {
return fmt.Sprintf("%s(@@%s@@)", v.Type().Yql(), string(v))
}
-func (jsonDocumentValue) Type() Type {
- return TypeJSONDocument
+func (jsonDocumentValue) Type() types.Type {
+ return types.JSONDocument
}
func (v jsonDocumentValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1053,7 +1174,7 @@ func JSONDocumentValue(v string) jsonDocumentValue {
}
type listValue struct {
- t Type
+ t types.Type
items []Value
}
@@ -1062,7 +1183,10 @@ func (v *listValue) ListItems() []Value {
}
func (v *listValue) castTo(dst interface{}) error {
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), dst))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), dst,
+ ))
}
func (v *listValue) Yql() string {
@@ -1076,10 +1200,11 @@ func (v *listValue) Yql() string {
buffer.WriteString(item.Yql())
}
buffer.WriteByte(']')
+
return buffer.String()
}
-func (v *listValue) Type() Type {
+func (v *listValue) Type() types.Type {
return v.t
}
@@ -1091,33 +1216,70 @@ func (v *listValue) toYDB(a *allocator.Allocator) *Ydb.Value {
vvv := a.Value()
for _, vv := range items {
- vvv.Items = append(vvv.Items, vv.toYDB(a))
+ vvv.Items = append(vvv.GetItems(), vv.toYDB(a))
}
return vvv
}
func ListValue(items ...Value) *listValue {
- var t Type
+ var t types.Type
switch {
case len(items) > 0:
- t = List(items[0].Type())
+ t = types.NewList(items[0].Type())
default:
- t = EmptyList()
+ t = types.NewEmptyList()
}
+
return &listValue{
t: t,
items: items,
}
}
+type pgValue struct {
+ t types.PgType
+ val string
+}
+
+func (v pgValue) castTo(dst interface{}) error {
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w PgType to '%T' destination",
+ ErrCannotCast, dst,
+ ))
+}
+
+func (v pgValue) Type() types.Type {
+ return v.t
+}
+
+func (v pgValue) toYDB(_ *allocator.Allocator) *Ydb.Value {
+ //nolint:godox
+ // TODO: make allocator
+ return &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: v.val,
+ },
+ }
+}
+
+func (v pgValue) Yql() string {
+ //nolint:godox
+ // TODO: call special function for unknown oids
+ // https://github.com/ydb-platform/ydb/issues/2706
+ return fmt.Sprintf(`PgConst("%v", PgType(%v))`, v.val, v.t.OID)
+}
+
type setValue struct {
- t Type
+ t types.Type
items []Value
}
func (v *setValue) castTo(dst interface{}) error {
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' to '%T' destination", v, dst))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' to '%T' destination",
+ ErrCannotCast, v, dst,
+ ))
}
func (v *setValue) Yql() string {
@@ -1131,10 +1293,11 @@ func (v *setValue) Yql() string {
buffer.WriteString(item.Yql())
}
buffer.WriteByte('}')
+
return buffer.String()
}
-func (v *setValue) Type() Type {
+func (v *setValue) Type() types.Type {
return v.t
}
@@ -1147,23 +1310,32 @@ func (v *setValue) toYDB(a *allocator.Allocator) *Ydb.Value {
pair.Key = vv.toYDB(a)
pair.Payload = _voidValue
- vvv.Pairs = append(vvv.Pairs, pair)
+ vvv.Pairs = append(vvv.GetPairs(), pair)
}
return vvv
}
+func PgValue(oid uint32, val string) pgValue {
+ return pgValue{
+ t: types.PgType{
+ OID: oid,
+ },
+ val: val,
+ }
+}
+
func SetValue(items ...Value) *setValue {
sort.Slice(items, func(i, j int) bool {
return items[i].Yql() < items[j].Yql()
})
- var t Type
+ var t types.Type
switch {
case len(items) > 0:
- t = Set(items[0].Type())
+ t = types.NewSet(items[0].Type())
default:
- t = EmptySet()
+ t = types.EmptySet()
}
return &setValue{
@@ -1172,35 +1344,66 @@ func SetValue(items ...Value) *setValue {
}
}
-func NullValue(t Type) *optionalValue {
+func NullValue(t types.Type) *optionalValue {
return &optionalValue{
- innerType: Optional(t),
+ innerType: types.NewOptional(t),
value: nil,
}
}
type optionalValue struct {
- innerType Type
+ innerType types.Type
value Value
}
-var errOptionalNilValue = errors.New("optional contains nil value")
-
func (v *optionalValue) castTo(dst interface{}) error {
+ ptr := reflect.ValueOf(dst)
+ if ptr.Kind() != reflect.Pointer {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: '%s'", errDestinationTypeIsNotAPointer, ptr.Kind().String()))
+ }
+
+ inner := reflect.Indirect(ptr)
+
+ if inner.Kind() != reflect.Pointer {
+ if v.value == nil {
+ if ptr.CanAddr() {
+ ptr.SetZero()
+ }
+
+ return nil
+ }
+
+ if err := v.value.castTo(ptr.Interface()); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+ }
+
if v.value == nil {
- return xerrors.WithStackTrace(errOptionalNilValue)
+ inner.SetZero()
+
+ return nil
}
- return v.value.castTo(dst)
+
+ inner.Set(reflect.New(inner.Type().Elem()))
+
+ if err := v.value.castTo(inner.Interface()); err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
}
func (v *optionalValue) Yql() string {
if v.value == nil {
return fmt.Sprintf("Nothing(%s)", v.Type().Yql())
}
+
return fmt.Sprintf("Just(%s)", v.value.Yql())
}
-func (v *optionalValue) Type() Type {
+func (v *optionalValue) Type() types.Type {
return v.innerType
}
@@ -1212,17 +1415,18 @@ func (v *optionalValue) toYDB(a *allocator.Allocator) *Ydb.Value {
vv.Value = vvv
} else {
if v.value != nil {
- vv.Value = v.value.toYDB(a).Value
+ vv = v.value.toYDB(a)
} else {
vv.Value = a.NullFlag()
}
}
+
return vv
}
func OptionalValue(v Value) *optionalValue {
return &optionalValue{
- innerType: Optional(v.Type()),
+ innerType: types.NewOptional(v.Type()),
value: v,
}
}
@@ -1233,7 +1437,7 @@ type (
V Value
}
structValue struct {
- t Type
+ t types.Type
fields []StructValueField
}
)
@@ -1243,11 +1447,15 @@ func (v *structValue) StructFields() map[string]Value {
for i := range v.fields {
fields[v.fields[i].Name] = v.fields[i].V
}
+
return fields
}
func (v *structValue) castTo(dst interface{}) error {
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' to '%T' destination", v, dst))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' to '%T' destination",
+ ErrCannotCast, v, dst,
+ ))
}
func (v *structValue) Yql() string {
@@ -1262,10 +1470,11 @@ func (v *structValue) Yql() string {
buffer.WriteString(v.fields[i].V.Yql())
}
buffer.WriteString("|>")
+
return buffer.String()
}
-func (v *structValue) Type() Type {
+func (v *structValue) Type() types.Type {
return v.t
}
@@ -1273,7 +1482,7 @@ func (v *structValue) toYDB(a *allocator.Allocator) *Ydb.Value {
vvv := a.Value()
for i := range v.fields {
- vvv.Items = append(vvv.Items, v.fields[i].V.toYDB(a))
+ vvv.Items = append(vvv.GetItems(), v.fields[i].V.toYDB(a))
}
return vvv
@@ -1283,12 +1492,16 @@ func StructValue(fields ...StructValueField) *structValue {
sort.Slice(fields, func(i, j int) bool {
return fields[i].Name < fields[j].Name
})
- structFields := make([]StructField, 0, len(fields))
+ structFields := make([]types.StructField, 0, len(fields))
for i := range fields {
- structFields = append(structFields, StructField{fields[i].Name, fields[i].V.Type()})
+ structFields = append(structFields, types.StructField{
+ Name: fields[i].Name,
+ T: fields[i].V.Type(),
+ })
}
+
return &structValue{
- t: Struct(structFields...),
+ t: types.NewStruct(structFields...),
fields: fields,
}
}
@@ -1299,12 +1512,17 @@ func (v timestampValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *time.Time:
*vv = TimestampToTime(uint64(v))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1312,8 +1530,8 @@ func (v timestampValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), TimestampToTime(uint64(v)).UTC().Format(LayoutTimestamp))
}
-func (timestampValue) Type() Type {
- return TypeTimestamp
+func (timestampValue) Type() types.Type {
+ return types.Timestamp
}
func (v timestampValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1336,7 +1554,7 @@ func TimestampValueFromTime(t time.Time) timestampValue {
}
type tupleValue struct {
- t Type
+ t types.Type
items []Value
}
@@ -1348,7 +1566,11 @@ func (v *tupleValue) castTo(dst interface{}) error {
if len(v.items) == 1 {
return v.items[0].castTo(dst)
}
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' to '%T' destination", v, dst))
+
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' to '%T' destination",
+ ErrCannotCast, v, dst,
+ ))
}
func (v *tupleValue) Yql() string {
@@ -1362,10 +1584,11 @@ func (v *tupleValue) Yql() string {
buffer.WriteString(item.Yql())
}
buffer.WriteByte(')')
+
return buffer.String()
}
-func (v *tupleValue) Type() Type {
+func (v *tupleValue) Type() types.Type {
return v.t
}
@@ -1377,19 +1600,20 @@ func (v *tupleValue) toYDB(a *allocator.Allocator) *Ydb.Value {
vvv := a.Value()
for _, vv := range items {
- vvv.Items = append(vvv.Items, vv.toYDB(a))
+ vvv.Items = append(vvv.GetItems(), vv.toYDB(a))
}
return vvv
}
func TupleValue(values ...Value) *tupleValue {
- tupleItems := make([]Type, 0, len(values))
+ tupleItems := make([]types.Type, 0, len(values))
for _, v := range values {
tupleItems = append(tupleItems, v.Type())
}
+
return &tupleValue{
- t: Tuple(tupleItems...),
+ t: types.NewTuple(tupleItems...),
items: values,
}
}
@@ -1400,12 +1624,17 @@ func (v tzDateValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1413,8 +1642,8 @@ func (v tzDateValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), string(v))
}
-func (tzDateValue) Type() Type {
- return TypeTzDate
+func (tzDateValue) Type() types.Type {
+ return types.TzDate
}
func (v tzDateValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1441,12 +1670,17 @@ func (v tzDatetimeValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1454,8 +1688,8 @@ func (v tzDatetimeValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), string(v))
}
-func (tzDatetimeValue) Type() Type {
- return TypeTzDatetime
+func (tzDatetimeValue) Type() types.Type {
+ return types.TzDatetime
}
func (v tzDatetimeValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1482,12 +1716,17 @@ func (v tzTimestampValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1495,8 +1734,8 @@ func (v tzTimestampValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), string(v))
}
-func (tzTimestampValue) Type() Type {
- return TypeTzTimestamp
+func (tzTimestampValue) Type() types.Type {
+ return types.TzTimestamp
}
func (v tzTimestampValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1523,39 +1762,53 @@ func (v uint8Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *uint32:
*vv = uint32(v)
+
return nil
case *int32:
*vv = int32(v)
+
return nil
case *uint16:
*vv = uint16(v)
+
return nil
case *int16:
*vv = int16(v)
+
return nil
case *uint8:
*vv = uint8(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
case *float32:
*vv = float32(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1563,8 +1816,8 @@ func (v uint8Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "ut"
}
-func (uint8Value) Type() Type {
- return TypeUint8
+func (uint8Value) Type() types.Type {
+ return types.Uint8
}
func (v uint8Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1587,33 +1840,45 @@ func (v uint16Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *uint32:
*vv = uint32(v)
+
return nil
case *int32:
*vv = int32(v)
+
return nil
case *uint16:
*vv = uint16(v)
+
return nil
case *float32:
*vv = float32(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1621,8 +1886,8 @@ func (v uint16Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "us"
}
-func (uint16Value) Type() Type {
- return TypeUint16
+func (uint16Value) Type() types.Type {
+ return types.Uint16
}
func (v uint16Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1645,24 +1910,33 @@ func (v uint32Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
case *int64:
*vv = int64(v)
+
return nil
case *uint32:
*vv = uint32(v)
+
return nil
case *float64:
*vv = float64(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1670,8 +1944,8 @@ func (v uint32Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "u"
}
-func (uint32Value) Type() Type {
- return TypeUint32
+func (uint32Value) Type() types.Type {
+ return types.Uint32
}
func (v uint32Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1694,15 +1968,21 @@ func (v uint64Value) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = strconv.FormatInt(int64(v), 10)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(strconv.FormatInt(int64(v), 10))
+
return nil
case *uint64:
*vv = uint64(v)
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1710,8 +1990,8 @@ func (v uint64Value) Yql() string {
return strconv.FormatUint(uint64(v), 10) + "ul"
}
-func (uint64Value) Type() Type {
- return TypeUint64
+func (uint64Value) Type() types.Type {
+ return types.Uint64
}
func (v uint64Value) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1734,12 +2014,17 @@ func (v textValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v)
+
return nil
case *[]byte:
*vv = xstring.ToBytes(string(v))
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1747,8 +2032,8 @@ func (v textValue) Yql() string {
return fmt.Sprintf("%qu", string(v))
}
-func (textValue) Type() Type {
- return TypeText
+func (textValue) Type() types.Type {
+ return types.Text
}
func (v textValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1773,15 +2058,21 @@ func (v *uuidValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = string(v.value[:])
+
return nil
case *[]byte:
*vv = v.value[:]
+
return nil
case *[16]byte:
*vv = v.value
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1794,11 +2085,12 @@ func (v *uuidValue) Yql() string {
buffer.WriteString(uuid.UUID(v.value).String())
buffer.WriteByte('"')
buffer.WriteByte(')')
+
return buffer.String()
}
-func (*uuidValue) Type() Type {
- return TypeUUID
+func (*uuidValue) Type() types.Type {
+ return types.UUID
}
func (v *uuidValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1821,15 +2113,15 @@ func UUIDValue(v [16]byte) *uuidValue {
}
type variantValue struct {
- innerType Type
+ innerType types.Type
value Value
idx uint32
}
func (v *variantValue) Variant() (name string, index uint32) {
switch t := v.innerType.(type) {
- case *variantStructType:
- return t.fields[v.idx].Name, v.idx
+ case *types.VariantStruct:
+ return t.Field(int(v.idx)).Name, v.idx
default:
return "", v.idx
}
@@ -1850,18 +2142,19 @@ func (v *variantValue) Yql() string {
buffer.WriteString(v.value.Yql())
buffer.WriteByte(',')
switch t := v.innerType.(type) {
- case *variantStructType:
- fmt.Fprintf(buffer, "%q", t.fields[v.idx].Name)
- case *variantTupleType:
+ case *types.VariantStruct:
+ fmt.Fprintf(buffer, "%q", t.Field(int(v.idx)).Name)
+ case *types.VariantTuple:
fmt.Fprintf(buffer, "\""+strconv.FormatUint(uint64(v.idx), 10)+"\"")
}
buffer.WriteByte(',')
buffer.WriteString(v.Type().Yql())
buffer.WriteByte(')')
+
return buffer.String()
}
-func (v *variantValue) Type() Type {
+func (v *variantValue) Type() types.Type {
return v.innerType
}
@@ -1877,10 +2170,11 @@ func (v *variantValue) toYDB(a *allocator.Allocator) *Ydb.Value {
return vvv
}
-func VariantValueTuple(v Value, idx uint32, t Type) *variantValue {
- if tt, has := t.(*TupleType); has {
- t = VariantTuple(tt.items...)
+func VariantValueTuple(v Value, idx uint32, t types.Type) *variantValue {
+ if tt, has := t.(*types.Tuple); has {
+ t = types.NewVariantTuple(tt.InnerTypes()...)
}
+
return &variantValue{
innerType: t,
value: v,
@@ -1888,25 +2182,28 @@ func VariantValueTuple(v Value, idx uint32, t Type) *variantValue {
}
}
-func VariantValueStruct(v Value, name string, t Type) *variantValue {
+func VariantValueStruct(v Value, name string, t types.Type) *variantValue {
var idx int
switch tt := t.(type) {
- case *StructType:
- sort.Slice(tt.fields, func(i, j int) bool {
- return tt.fields[i].Name < tt.fields[j].Name
+ case *types.Struct:
+ fields := tt.Fields()
+ sort.Slice(fields, func(i, j int) bool {
+ return fields[i].Name < fields[j].Name
})
- idx = sort.Search(len(tt.fields), func(i int) bool {
- return tt.fields[i].Name >= name
+ idx = sort.Search(len(fields), func(i int) bool {
+ return fields[i].Name >= name
})
- t = VariantStruct(tt.fields...)
- case *variantStructType:
- sort.Slice(tt.fields, func(i, j int) bool {
- return tt.fields[i].Name < tt.fields[j].Name
+ t = types.NewVariantStruct(fields...)
+ case *types.VariantStruct:
+ fields := tt.Fields()
+ sort.Slice(fields, func(i, j int) bool {
+ return fields[i].Name < fields[j].Name
})
- idx = sort.Search(len(tt.fields), func(i int) bool {
- return tt.fields[i].Name >= name
+ idx = sort.Search(len(fields), func(i int) bool {
+ return fields[i].Name >= name
})
}
+
return &variantValue{
innerType: t,
value: v,
@@ -1917,7 +2214,10 @@ func VariantValueStruct(v Value, name string, t Type) *variantValue {
type voidValue struct{}
func (v voidValue) castTo(dst interface{}) error {
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%s' to '%T' destination", v.Type().Yql(), dst))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%s' to '%T' destination",
+ ErrCannotCast, v.Type().Yql(), dst,
+ ))
}
func (v voidValue) Yql() string {
@@ -1925,13 +2225,13 @@ func (v voidValue) Yql() string {
}
var (
- _voidValueType = voidType{}
+ _voidValueType = types.Void{}
_voidValue = &Ydb.Value{
Value: new(Ydb.Value_NullFlagValue),
}
)
-func (voidValue) Type() Type {
+func (voidValue) Type() types.Type {
return _voidValueType
}
@@ -1949,12 +2249,17 @@ func (v ysonValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = xstring.FromBytes(v)
+
return nil
case *[]byte:
*vv = v
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -1962,8 +2267,8 @@ func (v ysonValue) Yql() string {
return fmt.Sprintf("%s(%q)", v.Type().Yql(), string(v))
}
-func (ysonValue) Type() Type {
- return TypeYSON
+func (ysonValue) Type() types.Type {
+ return types.YSON
}
func (v ysonValue) toYDB(a *allocator.Allocator) *Ydb.Value {
@@ -1982,81 +2287,81 @@ func YSONValue(v []byte) ysonValue {
return v
}
-func zeroPrimitiveValue(t PrimitiveType) Value {
+func zeroPrimitiveValue(t types.Primitive) Value {
switch t {
- case TypeBool:
+ case types.Bool:
return BoolValue(false)
- case TypeInt8:
+ case types.Int8:
return Int8Value(0)
- case TypeUint8:
+ case types.Uint8:
return Uint8Value(0)
- case TypeInt16:
+ case types.Int16:
return Int16Value(0)
- case TypeUint16:
+ case types.Uint16:
return Uint16Value(0)
- case TypeInt32:
+ case types.Int32:
return Int32Value(0)
- case TypeUint32:
+ case types.Uint32:
return Uint32Value(0)
- case TypeInt64:
+ case types.Int64:
return Int64Value(0)
- case TypeUint64:
+ case types.Uint64:
return Uint64Value(0)
- case TypeFloat:
+ case types.Float:
return FloatValue(0)
- case TypeDouble:
+ case types.Double:
return DoubleValue(0)
- case TypeDate:
+ case types.Date:
return DateValue(0)
- case TypeDatetime:
+ case types.Datetime:
return DatetimeValue(0)
- case TypeTimestamp:
+ case types.Timestamp:
return TimestampValue(0)
- case TypeInterval:
+ case types.Interval:
return IntervalValue(0)
- case TypeText:
+ case types.Text:
return TextValue("")
- case TypeYSON:
+ case types.YSON:
return YSONValue([]byte(""))
- case TypeJSON:
+ case types.JSON:
return JSONValue("")
- case TypeJSONDocument:
+ case types.JSONDocument:
return JSONDocumentValue("")
- case TypeDyNumber:
+ case types.DyNumber:
return DyNumberValue("")
- case TypeTzDate:
+ case types.TzDate:
return TzDateValue("")
- case TypeTzDatetime:
+ case types.TzDatetime:
return TzDatetimeValue("")
- case TypeTzTimestamp:
+ case types.TzTimestamp:
return TzTimestampValue("")
- case TypeBytes:
+ case types.Bytes:
return BytesValue([]byte{})
- case TypeUUID:
+ case types.UUID:
return UUIDValue([16]byte{})
default:
@@ -2064,53 +2369,57 @@ func zeroPrimitiveValue(t PrimitiveType) Value {
}
}
-func ZeroValue(t Type) Value {
+func ZeroValue(t types.Type) Value {
switch t := t.(type) {
- case PrimitiveType:
+ case types.Primitive:
return zeroPrimitiveValue(t)
- case optionalType:
- return NullValue(t.innerType)
+ case types.Optional:
+ return NullValue(t.InnerType())
- case *voidType:
+ case *types.Void:
return VoidValue()
- case *listType, *emptyListType:
+ case *types.List, *types.EmptyList:
return &listValue{
t: t,
}
- case *setType:
+ case *types.Set:
return &setValue{
t: t,
}
- case *dictType:
+ case *types.Dict:
return &dictValue{
- t: t.valueType,
+ t: t.ValueType(),
}
- case *emptyDictType:
+ case *types.EmptyDict:
return &dictValue{
t: t,
}
- case *TupleType:
+ case *types.Tuple:
return TupleValue(func() []Value {
- values := make([]Value, len(t.items))
- for i, tt := range t.items {
+ innerTypes := t.InnerTypes()
+ values := make([]Value, len(innerTypes))
+ for i, tt := range innerTypes {
values[i] = ZeroValue(tt)
}
+
return values
}()...)
- case *StructType:
+ case *types.Struct:
return StructValue(func() []StructValueField {
- fields := make([]StructValueField, len(t.fields))
- for i := range t.fields {
- fields[i] = StructValueField{
- Name: t.fields[i].Name,
- V: ZeroValue(t.fields[i].T),
+ fields := t.Fields()
+ values := make([]StructValueField, len(fields))
+ for i := range fields {
+ values[i] = StructValueField{
+ Name: fields[i].Name,
+ V: ZeroValue(fields[i].T),
}
}
- return fields
+
+ return values
}()...)
- case *DecimalType:
+ case *types.Decimal:
return DecimalValue([16]byte{}, 22, 9)
default:
@@ -2124,12 +2433,17 @@ func (v bytesValue) castTo(dst interface{}) error {
switch vv := dst.(type) {
case *string:
*vv = xstring.FromBytes(v)
+
return nil
case *[]byte:
*vv = v
+
return nil
default:
- return xerrors.WithStackTrace(fmt.Errorf("cannot cast '%+v' (type '%s') to '%T' destination", v, v.Type().Yql(), vv))
+ return xerrors.WithStackTrace(fmt.Errorf(
+ "%w '%+v' (type '%s') to '%T' destination",
+ ErrCannotCast, v, v.Type().Yql(), vv,
+ ))
}
}
@@ -2137,8 +2451,8 @@ func (v bytesValue) Yql() string {
return fmt.Sprintf("%q", string(v))
}
-func (bytesValue) Type() Type {
- return TypeBytes
+func (bytesValue) Type() types.Type {
+ return types.Bytes
}
func (v bytesValue) toYDB(a *allocator.Allocator) *Ydb.Value {
diff --git a/internal/value/value_test.go b/internal/value/value_test.go
index f2ea1fbe3..f7adfc7e9 100644
--- a/internal/value/value_test.go
+++ b/internal/value/value_test.go
@@ -1,8 +1,10 @@
package value
import (
+ "fmt"
"math"
"math/big"
+ "reflect"
"strconv"
"testing"
"time"
@@ -11,6 +13,9 @@ import (
"google.golang.org/protobuf/proto"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pg"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
)
func BenchmarkMemory(b *testing.B) {
@@ -68,24 +73,24 @@ func BenchmarkMemory(b *testing.B) {
DictValueField{TextValue("air_date"), Uint64Value(3)},
DictValueField{TextValue("remove_date"), Uint64Value(4)},
),
- NullValue(Optional(Optional(Optional(TypeBool)))),
- VariantValueTuple(Int32Value(42), 1, Tuple(
- TypeBytes,
- TypeInt32,
+ NullValue(types.NewOptional(types.NewOptional(types.NewOptional(types.Bool)))),
+ VariantValueTuple(Int32Value(42), 1, types.NewTuple(
+ types.Bytes,
+ types.Int32,
)),
- VariantValueStruct(Int32Value(42), "bar", Struct(
- StructField{
+ VariantValueStruct(Int32Value(42), "bar", types.NewStruct(
+ types.StructField{
Name: "foo",
- T: TypeBytes,
+ T: types.Bytes,
},
- StructField{
+ types.StructField{
Name: "bar",
- T: TypeInt32,
+ T: types.Int32,
},
)),
- ZeroValue(TypeText),
- ZeroValue(Struct()),
- ZeroValue(Tuple()),
+ ZeroValue(types.Text),
+ ZeroValue(types.NewStruct()),
+ ZeroValue(types.NewTuple()),
)
for i := 0; i < b.N; i++ {
a := allocator.New()
@@ -153,31 +158,32 @@ func TestToYDBFromYDB(t *testing.T) {
DictValueField{TextValue("air_date"), Uint64Value(3)},
DictValueField{TextValue("remove_date"), Uint64Value(4)},
),
- NullValue(TypeBool),
- NullValue(Optional(TypeBool)),
- VariantValueTuple(Int32Value(42), 1, Tuple(
- TypeBytes,
- TypeInt32,
+ NullValue(types.Bool),
+ NullValue(types.NewOptional(types.Bool)),
+ VariantValueTuple(Int32Value(42), 1, types.NewTuple(
+ types.Bytes,
+ types.Int32,
)),
- VariantValueStruct(Int32Value(42), "bar", Struct(
- StructField{
+ VariantValueStruct(Int32Value(42), "bar", types.NewStruct(
+ types.StructField{
Name: "foo",
- T: TypeBytes,
+ T: types.Bytes,
},
- StructField{
+ types.StructField{
Name: "bar",
- T: TypeInt32,
+ T: types.Int32,
},
)),
- ZeroValue(TypeText),
- ZeroValue(Struct()),
- ZeroValue(Tuple()),
+ ZeroValue(types.Text),
+ ZeroValue(types.NewStruct()),
+ ZeroValue(types.NewTuple()),
+ PgValue(pg.OIDInt4, "123"),
} {
t.Run(strconv.Itoa(i)+"."+v.Yql(), func(t *testing.T) {
a := allocator.New()
defer a.Free()
value := ToYDB(v, a)
- dualConversedValue, err := fromYDB(value.Type, value.Value)
+ dualConversedValue, err := fromYDB(value.GetType(), value.GetValue())
require.NoError(t, err)
if !proto.Equal(value, ToYDB(dualConversedValue, a)) {
t.Errorf("dual conversion failed:\n\n - got: %v\n\n - want: %v", ToYDB(dualConversedValue, a), value)
@@ -290,6 +296,7 @@ func TestValueYql(t *testing.T) {
{
value: DateValue(func() uint32 {
v, _ := time.Parse("2006-01-02", "2022-06-17")
+
return uint32(v.Sub(time.Unix(0, 0)) / time.Hour / 24)
}()),
literal: `Date("2022-06-17")`,
@@ -297,6 +304,7 @@ func TestValueYql(t *testing.T) {
{
value: DatetimeValue(func() uint32 {
v, _ := time.Parse("2006-01-02 15:04:05", "2022-06-17 05:19:20")
+
return uint32(v.UTC().Sub(time.Unix(0, 0)).Seconds())
}()),
literal: `Datetime("2022-06-17T05:19:20Z")`,
@@ -317,6 +325,7 @@ func TestValueYql(t *testing.T) {
value: TimestampValueFromTime(func() time.Time {
tt, err := time.Parse(LayoutTimestamp, "1997-12-14T03:09:42.123456Z")
require.NoError(t, err)
+
return tt.UTC()
}()),
literal: `Timestamp("1997-12-14T03:09:42.123456Z")`,
@@ -326,11 +335,11 @@ func TestValueYql(t *testing.T) {
literal: `TzTimestamp("1997-12-14T03:09:42.123456,Europe/Berlin")`,
},
{
- value: NullValue(TypeInt32),
+ value: NullValue(types.Int32),
literal: `Nothing(Optional)`,
},
{
- value: NullValue(Optional(TypeBool)),
+ value: NullValue(types.NewOptional(types.Bool)),
literal: `Nothing(Optional>)`,
},
{
@@ -387,30 +396,36 @@ func TestValueYql(t *testing.T) {
literal: `(0,1l,Float("2"),"3"u)`,
},
{
- value: VariantValueTuple(Int32Value(42), 1, Tuple(
- TypeBytes,
- TypeInt32,
+ value: VariantValueTuple(Int32Value(42), 1, types.NewTuple(
+ types.Bytes,
+ types.Int32,
)),
literal: `Variant(42,"1",Variant)`,
},
{
- value: VariantValueTuple(TextValue("foo"), 1, Tuple(
- TypeBytes,
- TypeText,
+ value: VariantValueTuple(TextValue("foo"), 1, types.NewTuple(
+ types.Bytes,
+ types.Text,
)),
literal: `Variant("foo"u,"1",Variant)`,
},
{
- value: VariantValueTuple(BoolValue(true), 0, Tuple(
- TypeBytes,
- TypeInt32,
+ value: VariantValueTuple(BoolValue(true), 0, types.NewTuple(
+ types.Bytes,
+ types.Int32,
)),
literal: `Variant(true,"0",Variant)`,
},
{
- value: VariantValueStruct(Int32Value(42), "bar", Struct(
- StructField{"foo", TypeBytes},
- StructField{"bar", TypeInt32},
+ value: VariantValueStruct(Int32Value(42), "bar", types.NewStruct(
+ types.StructField{
+ Name: "foo",
+ T: types.Bytes,
+ },
+ types.StructField{
+ Name: "bar",
+ T: types.Int32,
+ },
)),
literal: `Variant(42,"bar",Variant<'bar':Int32,'foo':String>)`,
},
@@ -437,26 +452,32 @@ func TestValueYql(t *testing.T) {
literal: `{"bar"u:Void(),"foo"u:Void()}`,
},
{
- value: ZeroValue(TypeBool),
+ value: ZeroValue(types.Bool),
literal: `false`,
},
{
- value: ZeroValue(Optional(TypeBool)),
+ value: ZeroValue(types.NewOptional(types.Bool)),
literal: `Nothing(Optional)`,
},
{
- value: ZeroValue(Tuple(TypeBool, TypeDouble)),
+ value: ZeroValue(types.NewTuple(types.Bool, types.Double)),
literal: `(false,Double("0"))`,
},
{
- value: ZeroValue(Struct(
- StructField{"foo", TypeBool},
- StructField{"bar", TypeText},
+ value: ZeroValue(types.NewStruct(
+ types.StructField{
+ Name: "foo",
+ T: types.Bool,
+ },
+ types.StructField{
+ Name: "bar",
+ T: types.Text,
+ },
)),
literal: "<|`bar`:\"\"u,`foo`:false|>",
},
{
- value: ZeroValue(TypeUUID),
+ value: ZeroValue(types.UUID),
literal: `Uuid("00000000-0000-0000-0000-000000000000")`,
},
{
@@ -479,9 +500,667 @@ func TestValueYql(t *testing.T) {
value: YSONValue([]byte("[3;%false]")),
literal: `Yson("[3;%false]")`,
},
+ {
+ value: PgValue(pg.OIDUnknown, "123"),
+ literal: `PgConst("123", PgType(705))`,
+ },
} {
t.Run(strconv.Itoa(i)+"."+tt.literal, func(t *testing.T) {
require.Equal(t, tt.literal, tt.value.Yql())
})
}
}
+
+func TestOptionalValueCastTo(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ v *optionalValue
+ dst **string
+ exp interface{}
+ err error
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ v: OptionalValue(TextValue("test")),
+ dst: func(v *string) **string { return &v }(func(s string) *string { return &s }("")),
+ exp: func(v *string) **string { return &v }(func(s string) *string { return &s }("test")),
+ err: nil,
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ v: OptionalValue(TextValue("test")),
+ dst: func(v *string) **string { return &v }(func() *string { return nil }()),
+ exp: func(v *string) **string { return &v }(func(s string) *string { return &s }("test")),
+ err: nil,
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ v: NullValue(types.Text),
+ dst: func(v *string) **string { return &v }(func(s string) *string { return &s }("")),
+ exp: func(v *string) **string { return &v }(func() *string { return nil }()),
+ err: nil,
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ v: NullValue(types.Text),
+ dst: func(v *string) **string { return &v }(func() *string { return nil }()),
+ exp: func(v *string) **string { return &v }(func() *string { return nil }()),
+ err: nil,
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ err := tt.v.castTo(tt.dst)
+ if tt.err != nil {
+ require.ErrorIs(t, err, tt.err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.exp, tt.dst)
+ }
+ })
+ }
+}
+
+func TestNullable(t *testing.T) {
+ for _, test := range []struct {
+ name string
+ t types.Type
+ v interface{}
+ exp Value
+ }{
+ {
+ name: "bool",
+ t: types.Bool,
+ v: func(v bool) *bool { return &v }(true),
+ exp: OptionalValue(BoolValue(true)),
+ },
+ {
+ name: "nil bool",
+ t: types.Bool,
+ v: func() *bool { return nil }(),
+ exp: NullValue(types.Bool),
+ },
+ {
+ name: "int8",
+ t: types.Int8,
+ v: func(v int8) *int8 { return &v }(123),
+ exp: OptionalValue(Int8Value(123)),
+ },
+ {
+ name: "nil int8",
+ t: types.Int8,
+ v: func() *int8 { return nil }(),
+ exp: NullValue(types.Int8),
+ },
+ {
+ name: "uint8",
+ t: types.Uint8,
+ v: func(v uint8) *uint8 { return &v }(123),
+ exp: OptionalValue(Uint8Value(123)),
+ },
+ {
+ name: "nil uint8",
+ t: types.Uint8,
+ v: func() *uint8 { return nil }(),
+ exp: NullValue(types.Uint8),
+ },
+ {
+ name: "int16",
+ t: types.Int16,
+ v: func(v int16) *int16 { return &v }(123),
+ exp: OptionalValue(Int16Value(123)),
+ },
+ {
+ name: "nil int16",
+ t: types.Int16,
+ v: func() *int16 { return nil }(),
+ exp: NullValue(types.Int16),
+ },
+ {
+ name: "uint16",
+ t: types.Uint16,
+ v: func(v uint16) *uint16 { return &v }(123),
+ exp: OptionalValue(Uint16Value(123)),
+ },
+ {
+ name: "nil uint16",
+ t: types.Uint16,
+ v: func() *uint16 { return nil }(),
+ exp: NullValue(types.Uint16),
+ },
+ {
+ name: "int32",
+ t: types.Int32,
+ v: func(v int32) *int32 { return &v }(123),
+ exp: OptionalValue(Int32Value(123)),
+ },
+ {
+ name: "nil int32",
+ t: types.Int32,
+ v: func() *int32 { return nil }(),
+ exp: NullValue(types.Int32),
+ },
+ {
+ name: "uint32",
+ t: types.Uint32,
+ v: func(v uint32) *uint32 { return &v }(123),
+ exp: OptionalValue(Uint32Value(123)),
+ },
+ {
+ name: "nil uint32",
+ t: types.Uint32,
+ v: func() *uint32 { return nil }(),
+ exp: NullValue(types.Uint32),
+ },
+ {
+ name: "int64",
+ t: types.Int64,
+ v: func(v int64) *int64 { return &v }(123),
+ exp: OptionalValue(Int64Value(123)),
+ },
+ {
+ name: "nil int64",
+ t: types.Int64,
+ v: func() *int64 { return nil }(),
+ exp: NullValue(types.Int64),
+ },
+ {
+ name: "uint64",
+ t: types.Uint64,
+ v: func(v uint64) *uint64 { return &v }(123),
+ exp: OptionalValue(Uint64Value(123)),
+ },
+ {
+ name: "nil uint64",
+ t: types.Uint64,
+ v: func() *uint64 { return nil }(),
+ exp: NullValue(types.Uint64),
+ },
+ {
+ name: "float",
+ t: types.Float,
+ v: func(v float32) *float32 { return &v }(123),
+ exp: OptionalValue(FloatValue(123)),
+ },
+ {
+ name: "nil float",
+ t: types.Float,
+ v: func() *float32 { return nil }(),
+ exp: NullValue(types.Float),
+ },
+ {
+ name: "double",
+ t: types.Double,
+ v: func(v float64) *float64 { return &v }(123),
+ exp: OptionalValue(DoubleValue(123)),
+ },
+ {
+ name: "nil float",
+ t: types.Double,
+ v: func() *float64 { return nil }(),
+ exp: NullValue(types.Double),
+ },
+ {
+ name: "date from int32",
+ t: types.Date,
+ v: func(v uint32) *uint32 { return &v }(123),
+ exp: OptionalValue(DateValue(123)),
+ },
+ {
+ name: "date from time.Time",
+ t: types.Date,
+ v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
+ exp: OptionalValue(DateValueFromTime(time.Unix(123, 456))),
+ },
+ {
+ name: "nil date",
+ t: types.Date,
+ v: func() *uint32 { return nil }(),
+ exp: NullValue(types.Date),
+ },
+ {
+ name: "datetime from int32",
+ t: types.Datetime,
+ v: func(v uint32) *uint32 { return &v }(123),
+ exp: OptionalValue(DatetimeValue(123)),
+ },
+ {
+ name: "datetime from time.Time",
+ t: types.Datetime,
+ v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
+ exp: OptionalValue(DatetimeValueFromTime(time.Unix(123, 456))),
+ },
+ {
+ name: "nil datetime",
+ t: types.Datetime,
+ v: func() *uint32 { return nil }(),
+ exp: NullValue(types.Datetime),
+ },
+ {
+ name: "timestamp from int32",
+ t: types.Timestamp,
+ v: func(v uint64) *uint64 { return &v }(123),
+ exp: OptionalValue(TimestampValue(123)),
+ },
+ {
+ name: "timestamp from time.Time",
+ t: types.Timestamp,
+ v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
+ exp: OptionalValue(TimestampValueFromTime(time.Unix(123, 456))),
+ },
+ {
+ name: "nil timestamp",
+ t: types.Timestamp,
+ v: func() *uint64 { return nil }(),
+ exp: NullValue(types.Timestamp),
+ },
+ {
+ name: "tzDate from int32",
+ t: types.TzDate,
+ v: func(v string) *string { return &v }(""),
+ exp: OptionalValue(TzDateValue("")),
+ },
+ {
+ name: "tzDate from time.Time",
+ t: types.TzDate,
+ v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
+ exp: OptionalValue(TzDateValueFromTime(time.Unix(123, 456))),
+ },
+ {
+ name: "nil tzDate",
+ t: types.TzDate,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.TzDate),
+ },
+ {
+ name: "interval from int64",
+ t: types.Interval,
+ v: func(v int64) *int64 { return &v }(123),
+ exp: OptionalValue(IntervalValue(123)),
+ },
+ {
+ name: "interval from time.Time",
+ t: types.Interval,
+ v: func(v time.Duration) *time.Duration { return &v }(time.Second),
+ exp: OptionalValue(IntervalValueFromDuration(time.Second)),
+ },
+ {
+ name: "nil interval",
+ t: types.Interval,
+ v: func() *int64 { return nil }(),
+ exp: NullValue(types.Interval),
+ },
+ {
+ name: "tzDatetime from int32",
+ t: types.TzDatetime,
+ v: func(v string) *string { return &v }(""),
+ exp: OptionalValue(TzDatetimeValue("")),
+ },
+ {
+ name: "tzTzDatetime from time.Time",
+ t: types.TzDatetime,
+ v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
+ exp: OptionalValue(TzDatetimeValueFromTime(time.Unix(123, 456))),
+ },
+ {
+ name: "nil tzTzDatetime",
+ t: types.TzDatetime,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.TzDatetime),
+ },
+ {
+ name: "tzTimestamp from int32",
+ t: types.TzTimestamp,
+ v: func(v string) *string { return &v }(""),
+ exp: OptionalValue(TzTimestampValue("")),
+ },
+ {
+ name: "TzTimestamp from time.Time",
+ t: types.TzTimestamp,
+ v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
+ exp: OptionalValue(TzTimestampValueFromTime(time.Unix(123, 456))),
+ },
+ {
+ name: "nil TzTimestamp",
+ t: types.TzTimestamp,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.TzTimestamp),
+ },
+ {
+ name: "string",
+ t: types.Bytes,
+ v: func(v string) *string { return &v }("test"),
+ exp: OptionalValue(BytesValue([]byte("test"))),
+ },
+ {
+ name: "string",
+ t: types.Bytes,
+ v: func(v []byte) *[]byte { return &v }([]byte("test")),
+ exp: OptionalValue(BytesValue([]byte("test"))),
+ },
+ {
+ name: "nil string",
+ t: types.Bytes,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.Bytes),
+ },
+ {
+ name: "utf8",
+ t: types.Text,
+ v: func(v string) *string { return &v }("test"),
+ exp: OptionalValue(TextValue("test")),
+ },
+ {
+ name: "nil utf8",
+ t: types.Text,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.Text),
+ },
+ {
+ name: "yson",
+ t: types.YSON,
+ v: func(v string) *string { return &v }("test"),
+ exp: OptionalValue(YSONValue([]byte("test"))),
+ },
+ {
+ name: "yson",
+ t: types.YSON,
+ v: func(v []byte) *[]byte { return &v }([]byte("test")),
+ exp: OptionalValue(YSONValue([]byte("test"))),
+ },
+ {
+ name: "nil yson",
+ t: types.YSON,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.YSON),
+ },
+ {
+ name: "json",
+ t: types.JSON,
+ v: func(v string) *string { return &v }("test"),
+ exp: OptionalValue(JSONValue("test")),
+ },
+ {
+ name: "json",
+ t: types.JSON,
+ v: func(v []byte) *[]byte { return &v }([]byte("test")),
+ exp: OptionalValue(JSONValue("test")),
+ },
+ {
+ name: "nil json",
+ t: types.JSON,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.JSON),
+ },
+ {
+ name: "uuid",
+ t: types.UUID,
+ v: func(v [16]byte) *[16]byte { return &v }([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}),
+ exp: OptionalValue(UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})),
+ },
+ {
+ name: "jsonDocument",
+ t: types.JSONDocument,
+ v: func(v string) *string { return &v }("test"),
+ exp: OptionalValue(JSONDocumentValue("test")),
+ },
+ {
+ name: "jsonDocument",
+ t: types.JSONDocument,
+ v: func(v []byte) *[]byte { return &v }([]byte("test")),
+ exp: OptionalValue(JSONDocumentValue("test")),
+ },
+ {
+ name: "nil jsonDocument",
+ t: types.JSONDocument,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.JSONDocument),
+ },
+ {
+ name: "dyNumber",
+ t: types.DyNumber,
+ v: func(v string) *string { return &v }("test"),
+ exp: OptionalValue(DyNumberValue("test")),
+ },
+ {
+ name: "nil dyNumber",
+ t: types.DyNumber,
+ v: func() *string { return nil }(),
+ exp: NullValue(types.DyNumber),
+ },
+ } {
+ t.Run(test.name, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ v := Nullable(test.t, test.v)
+ if !proto.Equal(ToYDB(v, a), ToYDB(test.exp, a)) {
+ t.Fatalf("unexpected value: %v, exp: %v", v, test.exp)
+ }
+ })
+ }
+}
+
+func TestCastNumbers(t *testing.T) {
+ numberValues := []struct {
+ value Value
+ signed bool
+ len int
+ }{
+ {
+ value: Uint64Value(1),
+ signed: false,
+ len: 8,
+ },
+ {
+ value: Int64Value(2),
+ signed: true,
+ len: 8,
+ },
+ {
+ value: Uint32Value(3),
+ signed: false,
+ len: 4,
+ },
+ {
+ value: Int32Value(4),
+ signed: true,
+ len: 4,
+ },
+ {
+ value: Uint16Value(5),
+ signed: false,
+ len: 2,
+ },
+ {
+ value: Int16Value(6),
+ signed: true,
+ len: 2,
+ },
+ {
+ value: Uint8Value(7),
+ signed: false,
+ len: 1,
+ },
+ {
+ value: Int8Value(8),
+ signed: true,
+ len: 1,
+ },
+ }
+ numberDestinations := []struct {
+ destination interface{}
+ signed bool
+ len int
+ }{
+ {
+ destination: func(v uint64) *uint64 { return &v }(1),
+ signed: false,
+ len: 8,
+ },
+ {
+ destination: func(v int64) *int64 { return &v }(2),
+ signed: true,
+ len: 8,
+ },
+ {
+ destination: func(v uint32) *uint32 { return &v }(3),
+ signed: false,
+ len: 4,
+ },
+ {
+ destination: func(v int32) *int32 { return &v }(4),
+ signed: true,
+ len: 4,
+ },
+ {
+ destination: func(v uint16) *uint16 { return &v }(5),
+ signed: false,
+ len: 2,
+ },
+ {
+ destination: func(v int16) *int16 { return &v }(6),
+ signed: true,
+ len: 2,
+ },
+ {
+ destination: func(v uint8) *uint8 { return &v }(7),
+ signed: false,
+ len: 1,
+ },
+ {
+ destination: func(v int8) *int8 { return &v }(8),
+ signed: true,
+ len: 1,
+ },
+ {
+ destination: func(v float32) *float32 { return &v }(7),
+ signed: true,
+ len: 4,
+ },
+ {
+ destination: func(v float64) *float64 { return &v }(8),
+ signed: true,
+ len: 8,
+ },
+ }
+ for _, dst := range numberDestinations {
+ for _, src := range numberValues {
+ t.Run(fmt.Sprintf("%s→%s",
+ src.value.Yql(), reflect.ValueOf(dst.destination).Type().Elem().String(),
+ ), func(t *testing.T) {
+ mustErr := false
+ switch {
+ case src.len == dst.len && src.signed != dst.signed,
+ src.len > dst.len,
+ src.signed && !dst.signed:
+ mustErr = true
+ }
+ err := CastTo(src.value, dst.destination)
+ if mustErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ t.Run(fmt.Sprintf("Optional(%s)→%s",
+ src.value.Yql(), reflect.ValueOf(dst.destination).Type().Elem().String(),
+ ), func(t *testing.T) {
+ mustErr := false
+ switch {
+ case src.len == dst.len && src.signed != dst.signed,
+ src.len > dst.len,
+ src.signed && !dst.signed:
+ mustErr = true
+ }
+ err := CastTo(OptionalValue(src.value), dst.destination)
+ if mustErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+ }
+}
+
+func TestCastOtherTypes(t *testing.T) {
+ for _, tt := range []struct {
+ v Value
+ dst interface{}
+ result interface{}
+ error bool
+ }{
+ {
+ v: BytesValue([]byte("test")),
+ dst: func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)),
+ result: func(v []byte) *[]byte { return &v }([]byte("test")),
+ error: false,
+ },
+ {
+ v: TextValue("test"),
+ dst: func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)),
+ result: func(v []byte) *[]byte { return &v }([]byte("test")),
+ error: false,
+ },
+ {
+ v: BytesValue([]byte("test")),
+ dst: func(v string) *string { return &v }(""),
+ result: func(v string) *string { return &v }("test"),
+ error: false,
+ },
+ {
+ v: DoubleValue(123),
+ dst: func(v float64) *float64 { return &v }(9),
+ result: func(v float64) *float64 { return &v }(123),
+ error: false,
+ },
+ {
+ v: DoubleValue(123),
+ dst: func(v float32) *float32 { return &v }(9),
+ result: func(v float32) *float32 { return &v }(9),
+ error: true,
+ },
+ {
+ v: FloatValue(123),
+ dst: func(v float64) *float64 { return &v }(9),
+ result: func(v float64) *float64 { return &v }(123),
+ error: false,
+ },
+ {
+ v: FloatValue(123),
+ dst: func(v float32) *float32 { return &v }(9),
+ result: func(v float32) *float32 { return &v }(123),
+ error: false,
+ },
+ {
+ v: Uint64Value(123),
+ dst: func(v float32) *float32 { return &v }(9),
+ result: func(v float32) *float32 { return &v }(9),
+ error: true,
+ },
+ {
+ v: Uint64Value(123),
+ dst: func(v float64) *float64 { return &v }(9),
+ result: func(v float64) *float64 { return &v }(9),
+ error: true,
+ },
+ {
+ v: OptionalValue(DoubleValue(123)),
+ dst: func(v float64) *float64 { return &v }(9),
+ result: func(v float64) *float64 { return &v }(123),
+ error: false,
+ },
+ } {
+ t.Run(fmt.Sprintf("%s→%v", tt.v.Type().Yql(), reflect.ValueOf(tt.dst).Type().Elem()),
+ func(t *testing.T) {
+ if err := CastTo(tt.v, tt.dst); (err != nil) != tt.error {
+ t.Errorf("castTo() error = %v, want %v", err, tt.error)
+ } else if !reflect.DeepEqual(tt.dst, tt.result) {
+ t.Errorf("castTo() result = %+v, want %+v",
+ reflect.ValueOf(tt.dst).Elem(),
+ reflect.ValueOf(tt.result).Elem(),
+ )
+ }
+ },
+ )
+ }
+}
diff --git a/internal/version/parse.go b/internal/version/parse.go
index f088defdb..e901ed031 100644
--- a/internal/version/parse.go
+++ b/internal/version/parse.go
@@ -33,6 +33,7 @@ func (lhs version) Less(rhs version) bool {
if lhs.Patch > rhs.Patch {
return false
}
+
return lhs.Suffix < rhs.Suffix
}
@@ -46,6 +47,7 @@ func Lt(lhs, rhs string) bool {
if err != nil {
return false
}
+
return v1.Less(v2)
}
@@ -62,6 +64,7 @@ func Gte(lhs, rhs string) bool {
if v1.Less(v2) {
return false
}
+
return true
}
@@ -89,5 +92,6 @@ func parse(s string) (v version, err error) {
return version{}, xerrors.WithStackTrace(err)
}
}
+
return v, nil
}
diff --git a/internal/version/version.go b/internal/version/version.go
index 1a57d5071..367b11e50 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -2,8 +2,8 @@ package version
const (
Major = "3"
- Minor = "55"
- Patch = "0"
+ Minor = "59"
+ Patch = "3"
Prefix = "ydb-go-sdk"
)
diff --git a/internal/wait/wait.go b/internal/wait/wait.go
index cdf41e355..11a01dee6 100644
--- a/internal/wait/wait.go
+++ b/internal/wait/wait.go
@@ -22,6 +22,7 @@ func waitBackoff(ctx context.Context, b backoff.Backoff, i int) error {
if err := ctx.Err(); err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
}
}
@@ -33,6 +34,7 @@ func Wait(ctx context.Context, fastBackoff, slowBackoff backoff.Backoff, t backo
if err := ctx.Err(); err != nil {
return xerrors.WithStackTrace(err)
}
+
return nil
case backoff.TypeFast:
if fastBackoff == nil {
@@ -45,5 +47,6 @@ func Wait(ctx context.Context, fastBackoff, slowBackoff backoff.Backoff, t backo
}
b = slowBackoff
}
+
return waitBackoff(ctx, b, i)
}
diff --git a/internal/xatomic/type.go b/internal/xatomic/type.go
deleted file mode 100644
index 0ce078b19..000000000
--- a/internal/xatomic/type.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package xatomic
-
-import "sync/atomic"
-
-type (
- Bool = atomic.Bool
- Int64 = atomic.Int64
- Uint32 = atomic.Uint32
- Uint64 = atomic.Uint64
-)
diff --git a/internal/xbytes/clone.go b/internal/xbytes/clone.go
deleted file mode 100644
index 0b471be25..000000000
--- a/internal/xbytes/clone.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package xbytes
-
-import "bytes"
-
-// Clone returns a copy of b[:len(b)].
-// The result may have additional unused capacity.
-// Clone(nil) returns nil.
-func Clone(b []byte) []byte {
- return bytes.Clone(b)
-}
diff --git a/internal/xcontext/context_error.go b/internal/xcontext/context_error.go
index ddd11553c..419ec12c9 100644
--- a/internal/xcontext/context_error.go
+++ b/internal/xcontext/context_error.go
@@ -4,7 +4,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
)
-var _ error = (*ctxErr)(nil)
+var _ error = (*ctxError)(nil)
const (
atWord = "at"
@@ -12,7 +12,7 @@ const (
)
func errAt(err error, skipDepth int) error {
- return &ctxErr{
+ return &ctxError{
err: err,
stackRecord: stack.Record(skipDepth + 1),
linkWord: atWord,
@@ -20,23 +20,23 @@ func errAt(err error, skipDepth int) error {
}
func errFrom(err error, from string) error {
- return &ctxErr{
+ return &ctxError{
err: err,
stackRecord: from,
linkWord: fromWord,
}
}
-type ctxErr struct {
+type ctxError struct {
err error
stackRecord string
linkWord string
}
-func (e *ctxErr) Error() string {
+func (e *ctxError) Error() string {
return "'" + e.err.Error() + "' " + e.linkWord + " `" + e.stackRecord + "`"
}
-func (e *ctxErr) Unwrap() error {
+func (e *ctxError) Unwrap() error {
return e.err
}
diff --git a/internal/xcontext/context_with_cancel.go b/internal/xcontext/context_with_cancel.go
index 7f983442c..1deeac4bb 100644
--- a/internal/xcontext/context_with_cancel.go
+++ b/internal/xcontext/context_with_cancel.go
@@ -11,6 +11,7 @@ func WithCancel(ctx context.Context) (context.Context, context.CancelFunc) {
parentCtx: ctx,
}
childCtx.ctx, childCtx.ctxCancel = context.WithCancel(ctx)
+
return childCtx, childCtx.cancel
}
@@ -60,6 +61,7 @@ func (ctx *cancelCtx) cancel() {
if err := ctx.parentCtx.Err(); err != nil {
ctx.err = err
+
return
}
ctx.err = errAt(context.Canceled, 1)
diff --git a/internal/xcontext/context_with_cancel_test.go b/internal/xcontext/context_with_cancel_test.go
index 515d1a7a7..55251b671 100644
--- a/internal/xcontext/context_with_cancel_test.go
+++ b/internal/xcontext/context_with_cancel_test.go
@@ -46,6 +46,7 @@ func TestContextWithCancelError(t *testing.T) {
childCtx, childCancel := WithCancel(parentCtx)
parentCancel()
childCancel()
+
return childCtx.Err()
}(),
str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithCancelError.func1(context_with_cancel_test.go:47)`", //nolint:lll
@@ -54,24 +55,27 @@ func TestContextWithCancelError(t *testing.T) {
err: func() error {
ctx, cancel := WithCancel(context.Background())
cancel()
+
return ctx.Err()
}(),
- str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithCancelError.func2(context_with_cancel_test.go:56)`", //nolint:lll
+ str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithCancelError.func2(context_with_cancel_test.go:57)`", //nolint:lll
},
{
err: func() error {
parentCtx, _ := WithTimeout(context.Background(), 0)
childCtx, cancel := WithCancel(parentCtx)
cancel()
+
return childCtx.Err()
}(),
- str: "'context deadline exceeded' from `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithCancelError.func3(context_with_cancel_test.go:63)`", //nolint:lll
+ str: "'context deadline exceeded' from `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithCancelError.func3(context_with_cancel_test.go:65)`", //nolint:lll
},
{
err: func() error {
parentCtx, _ := context.WithTimeout(context.Background(), 0) //nolint:govet
childCtx, cancel := WithCancel(parentCtx)
cancel()
+
return childCtx.Err()
}(),
str: "context deadline exceeded",
diff --git a/internal/xcontext/context_with_timeout.go b/internal/xcontext/context_with_timeout.go
index 72d067044..5342798fe 100644
--- a/internal/xcontext/context_with_timeout.go
+++ b/internal/xcontext/context_with_timeout.go
@@ -14,6 +14,7 @@ func WithTimeout(ctx context.Context, t time.Duration) (context.Context, context
from: stack.Record(1),
}
childCtx.ctx, childCtx.ctxCancel = context.WithTimeout(ctx, t)
+
return childCtx, childCtx.cancel
}
@@ -45,11 +46,13 @@ func (ctx *timeoutCtx) Err() error {
if ctx.ctx.Err() == context.DeadlineExceeded && ctx.parentCtx.Err() == nil { //nolint:errorlint
ctx.err = errFrom(context.DeadlineExceeded, ctx.from)
+
return ctx.err
}
if err := ctx.parentCtx.Err(); err != nil {
ctx.err = err
+
return ctx.err
}
@@ -72,6 +75,7 @@ func (ctx *timeoutCtx) cancel() {
if err := ctx.parentCtx.Err(); err != nil {
ctx.err = err
+
return
}
ctx.err = errAt(context.Canceled, 1)
diff --git a/internal/xcontext/context_with_timeout_test.go b/internal/xcontext/context_with_timeout_test.go
index 6286776b3..d29cfa2a2 100644
--- a/internal/xcontext/context_with_timeout_test.go
+++ b/internal/xcontext/context_with_timeout_test.go
@@ -47,6 +47,7 @@ func TestContextWithTimeoutError(t *testing.T) {
childCtx, childCancel := WithTimeout(parentCtx, time.Hour)
parentCancel()
childCancel()
+
return childCtx.Err()
}(),
str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func1(context_with_timeout_test.go:48)`", //nolint:lll
@@ -55,39 +56,44 @@ func TestContextWithTimeoutError(t *testing.T) {
err: func() error {
ctx, cancel := WithTimeout(context.Background(), time.Hour)
cancel()
+
return ctx.Err()
}(),
- str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func2(context_with_timeout_test.go:57)`", //nolint:lll
+ str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func2(context_with_timeout_test.go:58)`", //nolint:lll
},
{
err: func() error {
parentCtx, _ := WithTimeout(context.Background(), 0)
childCtx, _ := WithTimeout(parentCtx, 0)
+
return childCtx.Err()
}(),
- str: "'context deadline exceeded' from `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func3(context_with_timeout_test.go:64)`", //nolint:lll
+ str: "'context deadline exceeded' from `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func3(context_with_timeout_test.go:66)`", //nolint:lll
},
{
err: func() error {
ctx, _ := WithTimeout(context.Background(), 0)
+
return ctx.Err()
}(),
- str: "'context deadline exceeded' from `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func4(context_with_timeout_test.go:72)`", //nolint:lll
+ str: "'context deadline exceeded' from `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func4(context_with_timeout_test.go:75)`", //nolint:lll
},
{
err: func() error {
parentCtx, cancel := WithCancel(context.Background())
childCtx, _ := WithTimeout(parentCtx, 0)
cancel()
+
return childCtx.Err()
}(),
- str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func5(context_with_timeout_test.go:81)`", //nolint:lll
+ str: "'context canceled' at `github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext.TestContextWithTimeoutError.func5(context_with_timeout_test.go:85)`", //nolint:lll
},
{
err: func() error {
parentCtx, cancel := context.WithCancel(context.Background())
childCtx, _ := WithTimeout(parentCtx, 0)
cancel()
+
return childCtx.Err()
}(),
str: "context canceled",
diff --git a/internal/xcontext/idempotent.go b/internal/xcontext/idempotent.go
index 377b9f995..9e8c7577b 100644
--- a/internal/xcontext/idempotent.go
+++ b/internal/xcontext/idempotent.go
@@ -15,5 +15,6 @@ func IsIdempotent(ctx context.Context) bool {
if idempotent, ok := ctx.Value(ctxIdempotentKey{}).(bool); ok {
return idempotent
}
+
return false
}
diff --git a/internal/xcontext/local_dc.go b/internal/xcontext/local_dc.go
index d549d57da..01f0602fd 100644
--- a/internal/xcontext/local_dc.go
+++ b/internal/xcontext/local_dc.go
@@ -12,5 +12,6 @@ func ExtractLocalDC(ctx context.Context) string {
if val := ctx.Value(localDcKey{}); val != nil {
return val.(string)
}
+
return ""
}
diff --git a/internal/xcontext/retry_call.go b/internal/xcontext/retry_call.go
index 501895db3..e7e0789d7 100644
--- a/internal/xcontext/retry_call.go
+++ b/internal/xcontext/retry_call.go
@@ -14,5 +14,6 @@ func IsNestedCall(ctx context.Context) bool {
if _, has := ctx.Value(markRetryCallKey{}).(bool); has {
return true
}
+
return false
}
diff --git a/internal/xcontext/without_deadline.go b/internal/xcontext/without_deadline.go
index c0d92045c..2e80a284f 100644
--- a/internal/xcontext/without_deadline.go
+++ b/internal/xcontext/without_deadline.go
@@ -13,7 +13,7 @@ func (valueOnlyContext) Done() <-chan struct{} { return nil }
func (valueOnlyContext) Err() error { return nil }
-// WithoutDeadline helps to clear derived deadline from deadline
-func WithoutDeadline(ctx context.Context) context.Context {
+// ValueOnly helps to clear parent context from deadlines/cancels
+func ValueOnly(ctx context.Context) context.Context {
return valueOnlyContext{ctx}
}
diff --git a/internal/xerrors/check.go b/internal/xerrors/check.go
index 68864a986..2c6895f6b 100644
--- a/internal/xerrors/check.go
+++ b/internal/xerrors/check.go
@@ -9,7 +9,7 @@ func Check(err error) (
code int64,
errType Type,
backoffType backoff.Type,
- deleteSession bool,
+ invalidObject bool,
) {
if err == nil {
return -1,
@@ -19,18 +19,24 @@ func Check(err error) (
}
var e Error
if As(err, &e) {
- return int64(e.Code()), e.Type(), e.BackoffType(), e.MustDeleteSession()
+ return int64(e.Code()), e.Type(), e.BackoffType(), e.IsRetryObjectValid()
}
+
return -1,
TypeNonRetryable, // unknown errors are not retryable
backoff.TypeNoBackoff,
false
}
-func MustDeleteSession(err error) bool {
+func IsRetryObjectValid(err error) bool {
+ if err == nil {
+ return true
+ }
+
var e Error
if As(err, &e) {
- return e.MustDeleteSession()
+ return !e.IsRetryObjectValid()
}
- return false
+
+ return true
}
diff --git a/internal/xerrors/issues.go b/internal/xerrors/issues.go
index f4870b685..066bb94eb 100644
--- a/internal/xerrors/issues.go
+++ b/internal/xerrors/issues.go
@@ -44,19 +44,20 @@ func (ii issues) String() string {
b.WriteByte('\'')
b.WriteString(strings.TrimSuffix(m.GetMessage(), "."))
b.WriteByte('\'')
- if len(m.Issues) > 0 {
+ if len(m.GetIssues()) > 0 {
b.WriteByte(' ')
- b.WriteString(issues(m.Issues).String())
+ b.WriteString(issues(m.GetIssues()).String())
}
b.WriteByte('}')
}
b.WriteByte(']')
+
return b.String()
}
// NewWithIssues returns error which contains child issues
func NewWithIssues(text string, issues ...error) error {
- err := &errorWithIssues{
+ err := &withIssuesError{
reason: text,
}
for i := range issues {
@@ -64,17 +65,18 @@ func NewWithIssues(text string, issues ...error) error {
err.issues = append(err.issues, issues[i])
}
}
+
return err
}
-type errorWithIssues struct {
+type withIssuesError struct {
reason string
issues []error
}
-func (e *errorWithIssues) isYdbError() {}
+func (e *withIssuesError) isYdbError() {}
-func (e *errorWithIssues) Error() string {
+func (e *withIssuesError) Error() string {
var b bytes.Buffer
if len(e.reason) > 0 {
b.WriteString(e.reason)
@@ -89,24 +91,27 @@ func (e *errorWithIssues) Error() string {
b.WriteString(issue.Error())
}
b.WriteString("]")
+
return b.String()
}
-func (e *errorWithIssues) As(target interface{}) bool {
+func (e *withIssuesError) As(target interface{}) bool {
for _, err := range e.issues {
if As(err, target) {
return true
}
}
+
return false
}
-func (e *errorWithIssues) Is(target error) bool {
+func (e *withIssuesError) Is(target error) bool {
for _, err := range e.issues {
if Is(err, target) {
return true
}
}
+
return false
}
@@ -125,9 +130,10 @@ func (it IssueIterator) Len() int {
func (it IssueIterator) Get(i int) (issue Issue, nested IssueIterator) {
x := it[i]
- if xs := x.Issues; len(xs) > 0 {
+ if xs := x.GetIssues(); len(xs) > 0 {
nested = IssueIterator(xs)
}
+
return Issue{
Message: x.GetMessage(),
Code: x.GetIssueCode(),
diff --git a/internal/xerrors/join.go b/internal/xerrors/join.go
index b5b29d683..80ec421c1 100644
--- a/internal/xerrors/join.go
+++ b/internal/xerrors/join.go
@@ -7,43 +7,50 @@ import (
)
func Join(errs ...error) joinError {
- return errs
+ return joinError{
+ errs: errs,
+ }
}
-type joinError []error
+type joinError struct {
+ errs []error
+}
-func (errs joinError) Error() string {
+func (e joinError) Error() string {
b := xstring.Buffer()
defer b.Free()
b.WriteByte('[')
- for i, err := range errs {
+ for i, err := range e.errs {
if i > 0 {
_ = b.WriteByte(',')
}
_, _ = fmt.Fprintf(b, "%q", err.Error())
}
b.WriteByte(']')
+
return b.String()
}
-func (errs joinError) As(target interface{}) bool {
- for _, err := range errs {
+func (e joinError) As(target interface{}) bool {
+ for _, err := range e.errs {
if As(err, target) {
return true
}
}
+
return false
}
-func (errs joinError) Is(target error) bool {
- for _, err := range errs {
+func (e joinError) Is(target error) bool {
+ for _, err := range e.errs {
if Is(err, target) {
return true
}
}
+
return false
}
-func (errs joinError) Unwrap() []error {
- return errs
+func (e joinError) Unwrap() []error {
+ return e.errs
}
diff --git a/internal/xerrors/join_test.go b/internal/xerrors/join_test.go
index a3db6a55c..a9ff7e297 100644
--- a/internal/xerrors/join_test.go
+++ b/internal/xerrors/join_test.go
@@ -24,8 +24,12 @@ func TestJoin(t *testing.T) {
{
err: Join(context.Canceled, context.DeadlineExceeded, Operation()),
iss: []error{context.Canceled, context.DeadlineExceeded},
- ass: []interface{}{func() interface{} { var i isYdbError; return &i }()},
- s: "[\"context canceled\",\"context deadline exceeded\",\"operation/STATUS_CODE_UNSPECIFIED (code = 0)\"]",
+ ass: []interface{}{func() interface{} {
+ var i isYdbError
+
+ return &i
+ }()},
+ s: "[\"context canceled\",\"context deadline exceeded\",\"operation/STATUS_CODE_UNSPECIFIED (code = 0)\"]",
},
} {
t.Run("", func(t *testing.T) {
diff --git a/internal/xerrors/operation.go b/internal/xerrors/operation.go
index 36998f66e..7020e4f42 100644
--- a/internal/xerrors/operation.go
+++ b/internal/xerrors/operation.go
@@ -8,10 +8,11 @@ import (
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Issue"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/backoff"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
)
-// operationError reports about operationStatus fail.
+// operationError reports about operation fail.
type operationError struct {
code Ydb.StatusIds_StatusCode
issues issues
@@ -29,18 +30,13 @@ func (e *operationError) Name() string {
return "operation/" + e.code.String()
}
-type operationStatus interface {
- GetStatus() Ydb.StatusIds_StatusCode
- GetIssues() []*Ydb_Issue.IssueMessage
-}
-
type issuesOption []*Ydb_Issue.IssueMessage
func (issues issuesOption) applyToOperationError(oe *operationError) {
oe.issues = []*Ydb_Issue.IssueMessage(issues)
}
-// WithIssues is an option for construct operationStatus error with issues list
+// WithIssues is an option for construct operation error with issues list
// WithIssues must use as `Operation(WithIssues(issues))`
func WithIssues(issues []*Ydb_Issue.IssueMessage) issuesOption {
return issues
@@ -52,7 +48,7 @@ func (code statusCodeOption) applyToOperationError(oe *operationError) {
oe.code = Ydb.StatusIds_StatusCode(code)
}
-// WithStatusCode is an option for construct operationStatus error with reason code
+// WithStatusCode is an option for construct operation error with reason code
// WithStatusCode must use as `Operation(WithStatusCode(reason))`
func WithStatusCode(code Ydb.StatusIds_StatusCode) statusCodeOption {
return statusCodeOption(code)
@@ -72,24 +68,25 @@ func (traceID traceIDOption) applyToOperationError(oe *operationError) {
oe.traceID = string(traceID)
}
-// WithTraceID is an option for construct operationStatus error with traceID
+// WithTraceID is an option for construct operation error with traceID
func WithTraceID(traceID string) traceIDOption {
return traceIDOption(traceID)
}
-type operationOption struct {
- operationStatus
-}
+type operationOption = operationError
-func (operation operationOption) applyToOperationError(oe *operationError) {
- oe.code = operation.GetStatus()
- oe.issues = operation.GetIssues()
+func (e *operationOption) applyToOperationError(oe *operationError) {
+ oe.code = e.code
+ oe.issues = e.issues
}
-// FromOperation is an option for construct operationStatus error from operationStatus
-// FromOperation must use as `Operation(FromOperation(operationStatus))`
-func FromOperation(operation operationStatus) operationOption {
- return operationOption{operation}
+// FromOperation is an option for construct operation error from operation.Status
+// FromOperation must use as `Operation(FromOperation(operation.Status))`
+func FromOperation(operation operation.Status) *operationOption {
+ return &operationOption{
+ code: operation.GetStatus(),
+ issues: operation.GetIssues(),
+ }
}
type oeOpt interface {
@@ -105,6 +102,7 @@ func Operation(opts ...oeOpt) error {
opt.applyToOperationError(oe)
}
}
+
return oe
}
@@ -126,6 +124,7 @@ func (e *operationError) Error() string {
b.WriteString(e.issues.String())
}
b.WriteString(")")
+
return b.String()
}
@@ -143,6 +142,7 @@ func IsOperationError(err error, codes ...Ydb.StatusIds_StatusCode) bool {
return true
}
}
+
return false
}
@@ -154,6 +154,7 @@ func IsOperationErrorTransactionLocksInvalidated(err error) (isTLI bool) {
isTLI = isTLI || (code == issueCodeTransactionLocksInvalidated)
})
}
+
return isTLI
}
@@ -166,7 +167,9 @@ func (e *operationError) Type() Type {
Ydb.StatusIds_BAD_SESSION,
Ydb.StatusIds_SESSION_BUSY:
return TypeRetryable
- case Ydb.StatusIds_UNDETERMINED:
+ case
+ Ydb.StatusIds_UNDETERMINED,
+ Ydb.StatusIds_SESSION_EXPIRED:
return TypeConditionallyRetryable
default:
return TypeUndefined
@@ -189,7 +192,7 @@ func (e *operationError) BackoffType() backoff.Type {
}
}
-func (e *operationError) MustDeleteSession() bool {
+func (e *operationError) IsRetryObjectValid() bool {
switch e.code {
case
Ydb.StatusIds_BAD_SESSION,
@@ -206,5 +209,6 @@ func OperationError(err error) Error {
if errors.As(err, &o) {
return o
}
+
return nil
}
diff --git a/internal/xerrors/retryable.go b/internal/xerrors/retryable.go
index c2c2684ac..1c3141e8f 100644
--- a/internal/xerrors/retryable.go
+++ b/internal/xerrors/retryable.go
@@ -7,11 +7,11 @@ import (
)
type retryableError struct {
- name string
- err error
- backoffType backoff.Type
- mustDeleteSession bool
- code int32
+ name string
+ err error
+ backoffType backoff.Type
+ isRetryObjectValid bool
+ code int32
}
func (e *retryableError) Code() int32 {
@@ -30,8 +30,8 @@ func (e *retryableError) BackoffType() backoff.Type {
return e.backoffType
}
-func (e *retryableError) MustDeleteSession() bool {
- return e.mustDeleteSession
+func (e *retryableError) IsRetryObjectValid() bool {
+ return e.isRetryObjectValid
}
func (e *retryableError) Error() string {
@@ -56,9 +56,9 @@ func WithName(name string) RetryableErrorOption {
}
}
-func WithDeleteSession() RetryableErrorOption {
+func InvalidObject() RetryableErrorOption {
return func(e *retryableError) {
- e.mustDeleteSession = true
+ e.isRetryObjectValid = true
}
}
@@ -66,22 +66,24 @@ func Retryable(err error, opts ...RetryableErrorOption) error {
var (
e Error
re = &retryableError{
- err: err,
- name: "CUSTOM",
- code: -1,
+ err: err,
+ name: "CUSTOM",
+ code: -1,
+ isRetryObjectValid: true,
}
)
if As(err, &e) {
re.backoffType = e.BackoffType()
- re.mustDeleteSession = e.MustDeleteSession()
+ re.isRetryObjectValid = e.IsRetryObjectValid()
re.code = e.Code()
re.name = e.Name()
}
- for _, o := range opts {
- if o != nil {
- o(re)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(re)
}
}
+
return re
}
@@ -91,5 +93,6 @@ func RetryableError(err error) Error {
if errors.As(err, &e) {
return e
}
+
return nil
}
diff --git a/internal/xerrors/stacktrace.go b/internal/xerrors/stacktrace.go
index 4f2e2e6f0..3140547d5 100644
--- a/internal/xerrors/stacktrace.go
+++ b/internal/xerrors/stacktrace.go
@@ -24,9 +24,9 @@ func WithStackTrace(err error, opts ...withStackTraceOption) error {
return nil
}
options := withStackTraceOptions{}
- for _, o := range opts {
- if o != nil {
- o(&options)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&options)
}
}
if s, has := grpcStatus.FromError(err); has {
@@ -38,6 +38,7 @@ func WithStackTrace(err error, opts ...withStackTraceOption) error {
status: s,
}
}
+
return &stackError{
stackRecord: stack.Record(options.skipDepth + 1),
err: err,
diff --git a/internal/xerrors/transport.go b/internal/xerrors/transport.go
index 0a42b8b68..b66f7735c 100644
--- a/internal/xerrors/transport.go
+++ b/internal/xerrors/transport.go
@@ -58,6 +58,7 @@ func (e *transportError) Error() string {
b.WriteString(fmt.Sprintf(", traceID: %q", e.traceID))
}
b.WriteString(")")
+
return b.String()
}
@@ -97,7 +98,7 @@ func (e *transportError) BackoffType() backoff.Type {
}
}
-func (e *transportError) MustDeleteSession() bool {
+func (e *transportError) IsRetryObjectValid() bool {
switch e.status.Code() {
case
grpcCodes.ResourceExhausted,
@@ -129,6 +130,7 @@ func IsTransportError(err error, codes ...grpcCodes.Code) bool {
}
}
}
+
return false
}
@@ -139,7 +141,7 @@ func Transport(err error, opts ...teOpt) error {
}
var te *transportError
if errors.As(err, &te) {
- return err
+ return te
}
if s, ok := grpcStatus.FromError(err); ok {
te = &transportError{
@@ -157,6 +159,7 @@ func Transport(err error, opts ...teOpt) error {
opt.applyToTransportError(te)
}
}
+
return te
}
@@ -195,5 +198,6 @@ func TransportError(err error) Error {
err: err,
}
}
+
return nil
}
diff --git a/internal/xerrors/xerrors.go b/internal/xerrors/xerrors.go
index d0d4d0d44..ce6a20260 100644
--- a/internal/xerrors/xerrors.go
+++ b/internal/xerrors/xerrors.go
@@ -19,7 +19,7 @@ type Error interface {
Name() string
Type() Type
BackoffType() backoff.Type
- MustDeleteSession() bool
+ IsRetryObjectValid() bool
}
func IsTimeoutError(err error) bool {
@@ -46,6 +46,7 @@ func ErrIf(cond bool, err error) error {
if cond {
return err
}
+
return nil
}
@@ -56,6 +57,7 @@ func HideEOF(err error) error {
if errors.Is(err, io.EOF) {
return nil
}
+
return err
}
@@ -73,9 +75,16 @@ func As(err error, targets ...interface{}) bool {
return true
}
}
+
return false
}
+// IsErrorFromServer return true if err returned from server
+// (opposite to raised internally in sdk)
+func IsErrorFromServer(err error) bool {
+ return IsTransportError(err) || IsOperationError(err)
+}
+
// Is is a improved proxy to errors.Is
// This need to single import errors
func Is(err error, targets ...error) bool {
@@ -87,5 +96,10 @@ func Is(err error, targets ...error) bool {
return true
}
}
+
return false
}
+
+func IsContextError(err error) bool {
+ return Is(err, context.Canceled, context.DeadlineExceeded)
+}
diff --git a/internal/xerrors/ydb.go b/internal/xerrors/ydb.go
index 1a5995948..3c168703c 100644
--- a/internal/xerrors/ydb.go
+++ b/internal/xerrors/ydb.go
@@ -10,6 +10,7 @@ type isYdbError interface {
func IsYdb(err error) bool {
var e isYdbError
+
return errors.As(err, &e)
}
diff --git a/internal/xrand/xrand.go b/internal/xrand/xrand.go
index 8f2427c0d..2f8ed0021 100644
--- a/internal/xrand/xrand.go
+++ b/internal/xrand/xrand.go
@@ -35,11 +35,12 @@ func New(opts ...option) Rand {
r := &r{
r: rand.New(rand.NewSource(time.Now().Unix())), //nolint:gosec
}
- for _, o := range opts {
- if o != nil {
- o(r)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(r)
}
}
+
return r
}
diff --git a/internal/xresolver/xresolver.go b/internal/xresolver/xresolver.go
index 6ce395fa8..7eb2046a1 100644
--- a/internal/xresolver/xresolver.go
+++ b/internal/xresolver/xresolver.go
@@ -27,16 +27,18 @@ func (c *clientConn) Endpoint() string {
if endpoint == "" {
endpoint = c.target.URL.Opaque
}
+
return strings.TrimPrefix(endpoint, "/")
}
func (c *clientConn) UpdateState(state resolver.State) (err error) {
onDone := trace.DriverOnResolve(c.trace,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xresolver.(*clientConn).UpdateState"),
c.Endpoint(), func() (addrs []string) {
for i := range state.Addresses {
addrs = append(addrs, state.Addresses[i].Addr)
}
+
return
}(),
)
diff --git a/internal/xsql/badconn/badconn.go b/internal/xsql/badconn/badconn.go
index 620c674a2..54f5deb8c 100644
--- a/internal/xsql/badconn/badconn.go
+++ b/internal/xsql/badconn/badconn.go
@@ -24,6 +24,7 @@ func (e Error) Is(err error) bool {
if err == driver.ErrBadConn { //nolint:errorlint
return true
}
+
return xerrors.Is(e.err, err)
}
@@ -42,7 +43,7 @@ func Map(err error) error {
return nil
case xerrors.Is(err, io.EOF):
return io.EOF
- case xerrors.MustDeleteSession(err):
+ case !xerrors.IsRetryObjectValid(err):
return Error{err: err}
default:
return err
diff --git a/internal/xsql/badconn/badconn_test.go b/internal/xsql/badconn/badconn_test.go
index 1d252c051..7366542e2 100644
--- a/internal/xsql/badconn/badconn_test.go
+++ b/internal/xsql/badconn/badconn_test.go
@@ -45,12 +45,12 @@ var errsToCheck = []error{
xerrors.Retryable(
xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, "")),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
xerrors.Retryable(
grpcStatus.Error(grpcCodes.Unavailable, ""),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
xerrors.Transport(grpcStatus.Error(grpcCodes.DataLoss, "")),
xerrors.Transport(grpcStatus.Error(grpcCodes.Unauthenticated, "")),
@@ -112,7 +112,7 @@ var errsToCheck = []error{
xerrors.WithStatusCode(Ydb.StatusIds_SESSION_BUSY),
),
xerrors.Retryable(errors.New("retryable error")),
- xerrors.Retryable(errors.New("retryable error"), xerrors.WithDeleteSession()),
+ xerrors.Retryable(errors.New("retryable error"), xerrors.InvalidObject()),
io.EOF,
xerrors.WithStackTrace(io.EOF),
}
@@ -122,7 +122,7 @@ func Test_badConnError_Is(t *testing.T) {
t.Run(err.Error(), func(t *testing.T) {
err = Map(err)
require.Equal(t,
- xerrors.MustDeleteSession(err),
+ !xerrors.IsRetryObjectValid(err),
xerrors.Is(err, driver.ErrBadConn),
)
})
diff --git a/internal/xsql/conn.go b/internal/xsql/conn.go
index b5a52fd71..c5d670517 100644
--- a/internal/xsql/conn.go
+++ b/internal/xsql/conn.go
@@ -8,11 +8,12 @@ import (
"io"
"path"
"strings"
+ "sync/atomic"
"time"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/scheme/helpers"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn"
@@ -75,8 +76,8 @@ type conn struct {
beginTxFuncs map[QueryMode]beginTxFunc
- closed xatomic.Bool
- lastUsage xatomic.Int64
+ closed atomic.Bool
+ lastUsage atomic.Int64
defaultQueryMode QueryMode
defaultTxControl *table.TransactionControl
@@ -135,12 +136,13 @@ func newConn(ctx context.Context, c *Connector, s table.ClosableSession, opts ..
cc.beginTxFuncs = map[QueryMode]beginTxFunc{
DataQueryMode: cc.beginTx,
}
- for _, o := range opts {
- if o != nil {
- o(cc)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(cc)
}
}
c.attach(cc)
+
return cc
}
@@ -153,7 +155,7 @@ func (c *conn) PrepareContext(ctx context.Context, query string) (_ driver.Stmt,
return c.currentTx.PrepareContext(ctx, query)
}
onDone := trace.DatabaseSQLOnConnPrepare(c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).PrepareContext"),
query,
)
defer func() {
@@ -196,7 +198,7 @@ func (c *conn) execContext(ctx context.Context, query string, args []driver.Name
m = queryModeFromContext(ctx, c.defaultQueryMode)
onDone = trace.DatabaseSQLOnConnExec(
c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).execContext"),
query, m.String(), xcontext.IsIdempotent(ctx), c.sinceLastUsage(),
)
)
@@ -206,13 +208,13 @@ func (c *conn) execContext(ctx context.Context, query string, args []driver.Name
switch m {
case DataQueryMode:
- normalizedQuery, params, err := c.normalize(query, args...)
+ normalizedQuery, parameters, err := c.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
_, res, err := c.session.Execute(ctx,
txControl(ctx, c.defaultTxControl),
- normalizedQuery, params, c.dataQueryOptions(ctx)...,
+ normalizedQuery, ¶meters, c.dataQueryOptions(ctx)...,
)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
@@ -226,6 +228,7 @@ func (c *conn) execContext(ctx context.Context, query string, args []driver.Name
if err = res.Err(); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return resultNoRows{}, nil
case SchemeQueryMode:
normalizedQuery, _, err := c.normalize(query)
@@ -236,17 +239,15 @@ func (c *conn) execContext(ctx context.Context, query string, args []driver.Name
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return resultNoRows{}, nil
case ScriptingQueryMode:
- var (
- res result.StreamResult
- params *table.QueryParameters
- )
- normalizedQuery, params, err := c.normalize(query, args...)
+ var res result.StreamResult
+ normalizedQuery, parameters, err := c.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- res, err = c.connector.parent.Scripting().StreamExecute(ctx, normalizedQuery, params)
+ res, err = c.connector.parent.Scripting().StreamExecute(ctx, normalizedQuery, ¶meters)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
@@ -259,6 +260,7 @@ func (c *conn) execContext(ctx context.Context, query string, args []driver.Name
if err = res.Err(); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return resultNoRows{}, nil
default:
return nil, fmt.Errorf("unsupported query mode '%s' for execute query", m)
@@ -272,6 +274,7 @@ func (c *conn) ExecContext(ctx context.Context, query string, args []driver.Name
if c.currentTx != nil {
return c.currentTx.ExecContext(ctx, query, args)
}
+
return c.execContext(ctx, query, args)
}
@@ -282,6 +285,7 @@ func (c *conn) QueryContext(ctx context.Context, query string, args []driver.Nam
if c.currentTx != nil {
return c.currentTx.QueryContext(ctx, query, args)
}
+
return c.queryContext(ctx, query, args)
}
@@ -304,7 +308,7 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
m = queryModeFromContext(ctx, c.defaultQueryMode)
onDone = trace.DatabaseSQLOnConnQuery(
c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).queryContext"),
query, m.String(), xcontext.IsIdempotent(ctx), c.sinceLastUsage(),
)
)
@@ -314,13 +318,13 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
switch m {
case DataQueryMode:
- normalizedQuery, params, err := c.normalize(query, args...)
+ normalizedQuery, parameters, err := c.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
_, res, err := c.session.Execute(ctx,
txControl(ctx, c.defaultTxControl),
- normalizedQuery, params, c.dataQueryOptions(ctx)...,
+ normalizedQuery, ¶meters, c.dataQueryOptions(ctx)...,
)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
@@ -328,17 +332,18 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
if err = res.Err(); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return &rows{
conn: c,
result: res,
}, nil
case ScanQueryMode:
- normalizedQuery, params, err := c.normalize(query, args...)
+ normalizedQuery, parameters, err := c.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
res, err := c.session.StreamExecuteScanQuery(ctx,
- normalizedQuery, params, c.scanQueryOptions(ctx)...,
+ normalizedQuery, ¶meters, c.scanQueryOptions(ctx)...,
)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
@@ -346,6 +351,7 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
if err = res.Err(); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return &rows{
conn: c,
result: res,
@@ -359,6 +365,7 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return &single{
values: []sql.NamedArg{
sql.Named("AST", exp.AST),
@@ -366,17 +373,18 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
},
}, nil
case ScriptingQueryMode:
- normalizedQuery, params, err := c.normalize(query, args...)
+ normalizedQuery, parameters, err := c.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
- res, err := c.connector.parent.Scripting().StreamExecute(ctx, normalizedQuery, params)
+ res, err := c.connector.parent.Scripting().StreamExecute(ctx, normalizedQuery, ¶meters)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
if err = res.Err(); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return &rows{
conn: c,
result: res,
@@ -387,7 +395,9 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
}
func (c *conn) Ping(ctx context.Context) (finalErr error) {
- onDone := trace.DatabaseSQLOnConnPing(c.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.DatabaseSQLOnConnPing(c.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).Ping"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -397,6 +407,7 @@ func (c *conn) Ping(ctx context.Context) (finalErr error) {
if err := c.session.KeepAlive(ctx); err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
+
return nil
}
@@ -405,7 +416,7 @@ func (c *conn) Close() (finalErr error) {
c.connector.detach(c)
onDone := trace.DatabaseSQLOnConnClose(
c.trace, &c.openConnCtx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).Close"),
)
defer func() {
onDone(finalErr)
@@ -413,12 +424,14 @@ func (c *conn) Close() (finalErr error) {
if c.currentTx != nil {
_ = c.currentTx.Rollback()
}
- err := c.session.Close(xcontext.WithoutDeadline(c.openConnCtx))
+ err := c.session.Close(xcontext.ValueOnly(c.openConnCtx))
if err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
+
return nil
}
+
return badconn.Map(xerrors.WithStackTrace(errConnClosedEarly))
}
@@ -430,11 +443,12 @@ func (c *conn) Begin() (driver.Tx, error) {
return nil, errDeprecated
}
-func (c *conn) normalize(q string, args ...driver.NamedValue) (query string, _ *table.QueryParameters, _ error) {
+func (c *conn) normalize(q string, args ...driver.NamedValue) (query string, _ params.Parameters, _ error) {
return c.connector.Bindings.RewriteQuery(q, func() (ii []interface{}) {
for i := range args {
ii = append(ii, args[i])
}
+
return ii
}()...)
}
@@ -445,7 +459,9 @@ func (c *conn) ID() string {
func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ driver.Tx, finalErr error) {
var tx currentTx
- onDone := trace.DatabaseSQLOnConnBegin(c.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.DatabaseSQLOnConnBegin(c.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).BeginTx"),
+ )
defer func() {
onDone(tx, finalErr)
}()
@@ -453,10 +469,10 @@ func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ drive
if c.currentTx != nil {
return nil, xerrors.WithStackTrace(
xerrors.Retryable(
- &ErrConnAlreadyHaveTx{
+ &ConnAlreadyHaveTxError{
currentTx: c.currentTx.ID(),
},
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
)
}
@@ -469,7 +485,7 @@ func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ drive
xerrors.WithStackTrace(
xerrors.Retryable(
fmt.Errorf("wrong query mode: %s", m.String()),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
xerrors.WithName("WRONG_QUERY_MODE"),
),
),
@@ -487,13 +503,14 @@ func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ drive
func (c *conn) Version(_ context.Context) (_ string, _ error) {
const version = "default"
+
return version, nil
}
func (c *conn) IsTableExists(ctx context.Context, tableName string) (tableExists bool, finalErr error) {
tableName = c.normalizePath(tableName)
onDone := trace.DatabaseSQLOnConnIsTableExists(c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).IsTableExists"),
tableName,
)
defer func() {
@@ -506,6 +523,7 @@ func (c *conn) IsTableExists(ctx context.Context, tableName string) (tableExists
if err != nil {
return false, xerrors.WithStackTrace(err)
}
+
return tableExists, nil
}
@@ -530,14 +548,17 @@ func (c *conn) IsColumnExists(ctx context.Context, tableName, columnName string)
for i := range desc.Columns {
if desc.Columns[i].Name == columnName {
columnExists = true
+
break
}
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
return false, xerrors.WithStackTrace(err)
}
+
return columnExists, nil
}
@@ -562,11 +583,13 @@ func (c *conn) GetColumns(ctx context.Context, tableName string) (columns []stri
for i := range desc.Columns {
columns = append(columns, desc.Columns[i].Name)
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return columns, nil
}
@@ -599,14 +622,17 @@ func (c *conn) GetColumnType(ctx context.Context, tableName, columnName string)
for i := range desc.Columns {
if desc.Columns[i].Name == columnName {
dataType = desc.Columns[i].Type.Yql()
+
break
}
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
return "", xerrors.WithStackTrace(err)
}
+
return dataType, nil
}
@@ -629,11 +655,13 @@ func (c *conn) GetPrimaryKeys(ctx context.Context, tableName string) (pkCols []s
return err
}
pkCols = append(pkCols, desc.PrimaryKey...)
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return pkCols, nil
}
@@ -665,9 +693,11 @@ func (c *conn) IsPrimaryKey(ctx context.Context, tableName, columnName string) (
for _, pkCol := range pkCols {
if pkCol == columnName {
ok = true
+
break
}
}
+
return ok, nil
}
@@ -684,6 +714,7 @@ func isSysDir(databaseName, dirAbsPath string) bool {
return true
}
}
+
return false
}
@@ -697,6 +728,7 @@ func (c *conn) getTables(ctx context.Context, absPath string, recursive, exclude
var d scheme.Directory
err := retry.Retry(ctx, func(ctx context.Context) (err error) {
d, err = c.connector.parent.Scheme().ListDirectory(ctx, absPath)
+
return err
}, retry.WithIdempotent(true))
if err != nil {
@@ -733,6 +765,7 @@ func (c *conn) GetTables(ctx context.Context, folder string, recursive, excludeS
var e scheme.Entry
err := retry.Retry(ctx, func(ctx context.Context) (err error) {
e, err = c.connector.parent.Scheme().DescribePath(ctx, absPath)
+
return err
}, retry.WithIdempotent(true))
if err != nil {
@@ -751,6 +784,7 @@ func (c *conn) GetTables(ctx context.Context, folder string, recursive, excludeS
for i := range tables {
tables[i] = strings.TrimPrefix(tables[i], absPath+"/")
}
+
return tables, nil
default:
return nil, xerrors.WithStackTrace(
@@ -780,6 +814,7 @@ func (c *conn) GetIndexes(ctx context.Context, tableName string) (indexes []stri
for i := range desc.Indexes {
indexes = append(indexes, desc.Indexes[i].Name)
}
+
return nil
}, retry.WithIdempotent(true))
if err != nil {
@@ -810,9 +845,11 @@ func (c *conn) GetIndexColumns(ctx context.Context, tableName, indexName string)
for i := range desc.Indexes {
if desc.Indexes[i].Name == indexName {
columns = append(columns, desc.Indexes[i].IndexColumns...)
+
return nil
}
}
+
return xerrors.WithStackTrace(fmt.Errorf("index '%s' not found in table '%s'", indexName, tableName))
}, retry.WithIdempotent(true))
if err != nil {
diff --git a/internal/xsql/connector.go b/internal/xsql/connector.go
index 2812ac768..da43852e9 100644
--- a/internal/xsql/connector.go
+++ b/internal/xsql/connector.go
@@ -30,6 +30,7 @@ type defaultQueryModeConnectorOption QueryMode
func (mode defaultQueryModeConnectorOption) Apply(c *Connector) error {
c.defaultQueryMode = QueryMode(mode)
+
return nil
}
@@ -44,6 +45,7 @@ type queryBindConnectorOption struct {
func (o queryBindConnectorOption) Apply(c *Connector) error {
c.Bindings = bind.Sort(append(c.Bindings, o.Bind))
+
return nil
}
@@ -54,6 +56,7 @@ type tablePathPrefixConnectorOption struct {
func (o tablePathPrefixConnectorOption) Apply(c *Connector) error {
c.Bindings = bind.Sort(append(c.Bindings, o.TablePathPrefix))
c.pathNormalizer = o.TablePathPrefix
+
return nil
}
@@ -75,6 +78,7 @@ type defaultTxControlOption struct {
func (opt defaultTxControlOption) Apply(c *Connector) error {
c.defaultTxControl = opt.txControl
+
return nil
}
@@ -86,6 +90,7 @@ type defaultDataQueryOptionsConnectorOption []options.ExecuteDataQueryOption
func (opts defaultDataQueryOptionsConnectorOption) Apply(c *Connector) error {
c.defaultDataQueryOpts = append(c.defaultDataQueryOpts, opts...)
+
return nil
}
@@ -97,6 +102,7 @@ type defaultScanQueryOptionsConnectorOption []options.ExecuteScanQueryOption
func (opts defaultScanQueryOptionsConnectorOption) Apply(c *Connector) error {
c.defaultScanQueryOpts = append(c.defaultScanQueryOpts, opts...)
+
return nil
}
@@ -111,6 +117,7 @@ type traceConnectorOption struct {
func (option traceConnectorOption) Apply(c *Connector) error {
c.trace = c.trace.Compose(option.t, option.opts...)
+
return nil
}
@@ -122,6 +129,7 @@ type disableServerBalancerConnectorOption struct{}
func (d disableServerBalancerConnectorOption) Apply(c *Connector) error {
c.disableServerBalancer = true
+
return nil
}
@@ -133,6 +141,7 @@ type idleThresholdConnectorOption time.Duration
func (idleThreshold idleThresholdConnectorOption) Apply(c *Connector) error {
c.idleThreshold = time.Duration(idleThreshold)
+
return nil
}
@@ -144,6 +153,7 @@ type onCloseConnectorOption func(connector *Connector)
func (f onCloseConnectorOption) Apply(c *Connector) error {
c.onClose = append(c.onClose, f)
+
return nil
}
@@ -157,6 +167,7 @@ type traceRetryConnectorOption struct {
func (t traceRetryConnectorOption) Apply(c *Connector) error {
c.traceRetry = t.t
+
return nil
}
@@ -168,6 +179,7 @@ type fakeTxConnectorOption QueryMode
func (m fakeTxConnectorOption) Apply(c *Connector) error {
c.fakeTxModes = append(c.fakeTxModes, QueryMode(m))
+
return nil
}
@@ -203,6 +215,7 @@ func Open(parent ydbDriver, opts ...ConnectorOption) (_ *Connector, err error) {
if c.idleThreshold > 0 {
c.idleStopper = c.idleCloser()
}
+
return c, nil
}
@@ -267,6 +280,7 @@ func (c *Connector) idleCloser() (idleStopper func()) {
}
}
}()
+
return idleStopper
}
@@ -279,6 +293,7 @@ func (c *Connector) Close() (err error) {
if c.idleStopper != nil {
c.idleStopper()
}
+
return nil
}
@@ -298,7 +313,7 @@ func (c *Connector) Connect(ctx context.Context) (_ driver.Conn, err error) {
var (
onDone = trace.DatabaseSQLOnConnectorConnect(
c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*Connector).Connect"),
)
session table.ClosableSession
)
diff --git a/internal/xsql/context.go b/internal/xsql/context.go
index 0b694e118..af1516de0 100644
--- a/internal/xsql/context.go
+++ b/internal/xsql/context.go
@@ -31,6 +31,7 @@ func queryModeFromContext(ctx context.Context, defaultQueryMode QueryMode) Query
if m, ok := ctx.Value(ctxModeTypeKey{}).(QueryMode); ok {
return m
}
+
return defaultQueryMode
}
@@ -47,6 +48,7 @@ func txControl(ctx context.Context, defaultTxControl *table.TransactionControl)
if txc, ok := ctx.Value(ctxTransactionControlKey{}).(*table.TransactionControl); ok {
return txc
}
+
return defaultTxControl
}
@@ -64,6 +66,7 @@ func (c *conn) scanQueryOptions(ctx context.Context) []options.ExecuteScanQueryO
if opts, ok := ctx.Value(ctxScanQueryOptionsKey{}).([]options.ExecuteScanQueryOption); ok {
return append(c.scanOpts, opts...)
}
+
return c.scanOpts
}
@@ -81,6 +84,7 @@ func (c *conn) dataQueryOptions(ctx context.Context) []options.ExecuteDataQueryO
if opts, ok := ctx.Value(ctxDataQueryOptionsKey{}).([]options.ExecuteDataQueryOption); ok {
return append(c.dataOpts, opts...)
}
+
return c.dataOpts
}
diff --git a/internal/xsql/dsn.go b/internal/xsql/dsn.go
index 5fbff80ce..508308995 100644
--- a/internal/xsql/dsn.go
+++ b/internal/xsql/dsn.go
@@ -79,6 +79,7 @@ func Parse(dataSourceName string) (opts []config.Option, connectorOpts []Connect
}
connectorOpts = append(connectorOpts, binders...)
}
+
return opts, connectorOpts, nil
}
@@ -92,5 +93,6 @@ func extractTablePathPrefixFromBinderName(binderName string) (string, error) {
if len(ss) != 1 || len(ss[0]) != 2 || ss[0][1] == "" {
return "", xerrors.WithStackTrace(fmt.Errorf("%w: %s", errWrongTablePathPrefix, binderName))
}
+
return ss[0][1], nil
}
diff --git a/internal/xsql/dsn_test.go b/internal/xsql/dsn_test.go
index 309f9bf6a..d28c96ac3 100644
--- a/internal/xsql/dsn_test.go
+++ b/internal/xsql/dsn_test.go
@@ -13,10 +13,13 @@ func TestParse(t *testing.T) {
newConnector := func(opts ...ConnectorOption) *Connector {
c := &Connector{}
for _, opt := range opts {
- if err := opt.Apply(c); err != nil {
- t.Error(err)
+ if opt != nil {
+ if err := opt.Apply(c); err != nil {
+ t.Error(err)
+ }
}
}
+
return c
}
compareConfigs := func(t *testing.T, lhs, rhs *config.Config) {
diff --git a/internal/xsql/errors.go b/internal/xsql/errors.go
index 65c36486d..8dbcc7ce9 100644
--- a/internal/xsql/errors.go
+++ b/internal/xsql/errors.go
@@ -10,22 +10,23 @@ import (
var (
ErrUnsupported = driver.ErrSkip
errDeprecated = driver.ErrSkip
- errConnClosedEarly = xerrors.Retryable(errors.New("conn closed early"), xerrors.WithDeleteSession())
- errNotReadyConn = xerrors.Retryable(errors.New("conn not ready"), xerrors.WithDeleteSession())
+ errConnClosedEarly = xerrors.Retryable(errors.New("conn closed early"), xerrors.InvalidObject())
+ errNotReadyConn = xerrors.Retryable(errors.New("conn not ready"), xerrors.InvalidObject())
)
-type ErrConnAlreadyHaveTx struct {
+type ConnAlreadyHaveTxError struct {
currentTx string
}
-func (err *ErrConnAlreadyHaveTx) Error() string {
+func (err *ConnAlreadyHaveTxError) Error() string {
return "conn already have an open currentTx: " + err.currentTx
}
-func (err *ErrConnAlreadyHaveTx) As(target interface{}) bool {
+func (err *ConnAlreadyHaveTxError) As(target interface{}) bool {
switch t := target.(type) {
- case *ErrConnAlreadyHaveTx:
+ case *ConnAlreadyHaveTxError:
t.currentTx = err.currentTx
+
return true
default:
return false
diff --git a/internal/xsql/isolation/isolation.go b/internal/xsql/isolation/isolation.go
index 2b1f026cf..e7f6a7b9d 100644
--- a/internal/xsql/isolation/isolation.go
+++ b/internal/xsql/isolation/isolation.go
@@ -25,6 +25,7 @@ func ToYDB(opts driver.TxOptions) (txcControl table.TxOption, err error) {
return table.WithSnapshotReadOnly(), nil
}
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf(
"unsupported transaction options: %+v", opts,
))
diff --git a/internal/xsql/mode.go b/internal/xsql/mode.go
index 0070020c0..298bbd64e 100644
--- a/internal/xsql/mode.go
+++ b/internal/xsql/mode.go
@@ -36,6 +36,7 @@ func (t QueryMode) String() string {
if s, ok := typeToString[t]; ok {
return s
}
+
return fmt.Sprintf("unknown_mode_%d", t)
}
@@ -43,5 +44,6 @@ func QueryModeFromString(s string) QueryMode {
if t, ok := stringToType[s]; ok {
return t
}
+
return UnknownQueryMode
}
diff --git a/internal/xsql/rows.go b/internal/xsql/rows.go
index b3adf339b..a9bb1572e 100644
--- a/internal/xsql/rows.go
+++ b/internal/xsql/rows.go
@@ -5,14 +5,15 @@ import (
"database/sql"
"database/sql/driver"
"io"
+ "strings"
"sync"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/scanner"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/indexed"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
var (
@@ -22,7 +23,9 @@ var (
_ driver.RowsColumnTypeNullable = &rows{}
_ driver.Rows = &single{}
- _ types.Scanner = &valuer{}
+ _ scanner.Scanner = &valuer{}
+
+ ignoreColumnPrefixName = "__discard_column_"
)
type rows struct {
@@ -43,8 +46,11 @@ func (r *rows) Columns() []string {
})
cs := make([]string, 0, r.result.CurrentResultSet().ColumnCount())
r.result.CurrentResultSet().Columns(func(m options.Column) {
- cs = append(cs, m.Name)
+ if !strings.HasPrefix(m.Name, ignoreColumnPrefixName) {
+ cs = append(cs, m.Name)
+ }
})
+
return cs
}
@@ -92,6 +98,7 @@ func (r *rows) NextResultSet() (finalErr error) {
if err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
+
return nil
}
@@ -126,6 +133,7 @@ func (r *rows) Next(dst []driver.Value) error {
if err = r.result.Err(); err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
+
return nil
}
@@ -142,6 +150,7 @@ func (r *single) Columns() (columns []string) {
for i := range r.values {
columns = append(columns, r.values[i].Name)
}
+
return columns
}
@@ -157,5 +166,6 @@ func (r *single) Next(dst []driver.Value) error {
dst[i] = r.values[i].Value
}
r.readAll = true
+
return nil
}
diff --git a/internal/xsql/stmt.go b/internal/xsql/stmt.go
index 99d1d3131..75b571acd 100644
--- a/internal/xsql/stmt.go
+++ b/internal/xsql/stmt.go
@@ -31,7 +31,7 @@ var (
func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (_ driver.Rows, finalErr error) {
onDone := trace.DatabaseSQLOnStmtQuery(s.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*stmt).QueryContext"),
s.stmtCtx, s.query,
)
defer func() {
@@ -50,7 +50,7 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (_ dr
func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (_ driver.Result, finalErr error) {
onDone := trace.DatabaseSQLOnStmtExec(s.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*stmt).ExecContext"),
s.stmtCtx, s.query,
)
defer func() {
@@ -72,10 +72,13 @@ func (s *stmt) NumInput() int {
}
func (s *stmt) Close() (finalErr error) {
- onDone := trace.DatabaseSQLOnStmtClose(s.trace, &s.stmtCtx, stack.FunctionID(""))
+ onDone := trace.DatabaseSQLOnStmtClose(s.trace, &s.stmtCtx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*stmt).Close"),
+ )
defer func() {
onDone(finalErr)
}()
+
return nil
}
diff --git a/internal/xsql/tx.go b/internal/xsql/tx.go
index 5a135c0c9..d67813437 100644
--- a/internal/xsql/tx.go
+++ b/internal/xsql/tx.go
@@ -49,6 +49,7 @@ func (c *conn) beginTx(ctx context.Context, txOptions driver.TxOptions) (current
txCtx: ctx,
tx: transaction,
}
+
return c.currentTx, nil
}
@@ -65,6 +66,7 @@ func (tx *tx) checkTxState() error {
tx.ID(), tx.conn.ID(),
)
}
+
return fmt.Errorf("broken conn state: tx=%s not related to conn=%q (conn have current tx=%q)",
tx.conn.currentTx.ID(), tx.conn.ID(), tx.ID(),
)
@@ -72,7 +74,7 @@ func (tx *tx) checkTxState() error {
func (tx *tx) Commit() (finalErr error) {
onDone := trace.DatabaseSQLOnTxCommit(tx.conn.trace, &tx.txCtx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).Commit"),
tx,
)
defer func() {
@@ -88,12 +90,13 @@ func (tx *tx) Commit() (finalErr error) {
if err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
+
return nil
}
func (tx *tx) Rollback() (finalErr error) {
onDone := trace.DatabaseSQLOnTxRollback(tx.conn.trace, &tx.txCtx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).Rollback"),
tx,
)
defer func() {
@@ -109,6 +112,7 @@ func (tx *tx) Rollback() (finalErr error) {
if err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
+
return err
}
@@ -116,8 +120,8 @@ func (tx *tx) QueryContext(ctx context.Context, query string, args []driver.Name
_ driver.Rows, finalErr error,
) {
onDone := trace.DatabaseSQLOnTxQuery(tx.conn.trace, &ctx,
- stack.FunctionID(""),
- tx.txCtx, tx, query, true,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).QueryContext"),
+ tx.txCtx, tx, query,
)
defer func() {
onDone(finalErr)
@@ -128,18 +132,18 @@ func (tx *tx) QueryContext(ctx context.Context, query string, args []driver.Name
xerrors.WithStackTrace(
xerrors.Retryable(
fmt.Errorf("wrong query mode: %s", m.String()),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
xerrors.WithName("WRONG_QUERY_MODE"),
),
),
)
}
- query, params, err := tx.conn.normalize(query, args...)
+ query, parameters, err := tx.conn.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
res, err := tx.tx.Execute(ctx,
- query, params, tx.conn.dataQueryOptions(ctx)...,
+ query, ¶meters, tx.conn.dataQueryOptions(ctx)...,
)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
@@ -147,6 +151,7 @@ func (tx *tx) QueryContext(ctx context.Context, query string, args []driver.Name
if err = res.Err(); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return &rows{
conn: tx.conn,
result: res,
@@ -157,8 +162,8 @@ func (tx *tx) ExecContext(ctx context.Context, query string, args []driver.Named
_ driver.Result, finalErr error,
) {
onDone := trace.DatabaseSQLOnTxExec(tx.conn.trace, &ctx,
- stack.FunctionID(""),
- tx.txCtx, tx, query, true,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).ExecContext"),
+ tx.txCtx, tx, query,
)
defer func() {
onDone(finalErr)
@@ -169,28 +174,29 @@ func (tx *tx) ExecContext(ctx context.Context, query string, args []driver.Named
xerrors.WithStackTrace(
xerrors.Retryable(
fmt.Errorf("wrong query mode: %s", m.String()),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
xerrors.WithName("WRONG_QUERY_MODE"),
),
),
)
}
- query, params, err := tx.conn.normalize(query, args...)
+ query, parameters, err := tx.conn.normalize(query, args...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
_, err = tx.tx.Execute(ctx,
- query, params, tx.conn.dataQueryOptions(ctx)...,
+ query, ¶meters, tx.conn.dataQueryOptions(ctx)...,
)
if err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return resultNoRows{}, nil
}
func (tx *tx) PrepareContext(ctx context.Context, query string) (_ driver.Stmt, finalErr error) {
onDone := trace.DatabaseSQLOnTxPrepare(tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).PrepareContext"),
&tx.txCtx, tx, query,
)
defer func() {
@@ -199,6 +205,7 @@ func (tx *tx) PrepareContext(ctx context.Context, query string) (_ driver.Stmt,
if !tx.conn.isReady() {
return nil, badconn.Map(xerrors.WithStackTrace(errNotReadyConn))
}
+
return &stmt{
conn: tx.conn,
processor: tx,
diff --git a/internal/xsql/tx_fake.go b/internal/xsql/tx_fake.go
index 1488e00b6..459aba718 100644
--- a/internal/xsql/tx_fake.go
+++ b/internal/xsql/tx_fake.go
@@ -5,7 +5,6 @@ import (
"database/sql/driver"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
@@ -20,7 +19,7 @@ type txFake struct {
func (tx *txFake) PrepareContext(ctx context.Context, query string) (_ driver.Stmt, finalErr error) {
onDone := trace.DatabaseSQLOnTxPrepare(tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).PrepareContext"),
&tx.beginCtx, tx, query,
)
defer func() {
@@ -29,6 +28,7 @@ func (tx *txFake) PrepareContext(ctx context.Context, query string) (_ driver.St
if !tx.conn.isReady() {
return nil, badconn.Map(xerrors.WithStackTrace(errNotReadyConn))
}
+
return &stmt{
conn: tx.conn,
processor: tx,
@@ -58,7 +58,7 @@ func (tx *txFake) ID() string {
func (tx *txFake) Commit() (err error) {
onDone := trace.DatabaseSQLOnTxCommit(tx.conn.trace, &tx.ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).Commit"),
tx,
)
defer func() {
@@ -70,12 +70,13 @@ func (tx *txFake) Commit() (err error) {
if !tx.conn.isReady() {
return badconn.Map(xerrors.WithStackTrace(errNotReadyConn))
}
+
return nil
}
func (tx *txFake) Rollback() (err error) {
onDone := trace.DatabaseSQLOnTxRollback(tx.conn.trace, &tx.ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).Rollback"),
tx,
)
defer func() {
@@ -87,6 +88,7 @@ func (tx *txFake) Rollback() (err error) {
if !tx.conn.isReady() {
return badconn.Map(xerrors.WithStackTrace(errNotReadyConn))
}
+
return err
}
@@ -95,8 +97,8 @@ func (tx *txFake) QueryContext(ctx context.Context, query string, args []driver.
) {
onDone := trace.DatabaseSQLOnTxQuery(
tx.conn.trace, &ctx,
- stack.FunctionID(""),
- tx.ctx, tx, query, xcontext.IsIdempotent(ctx),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).QueryContext"),
+ tx.ctx, tx, query,
)
defer func() {
onDone(err)
@@ -105,6 +107,7 @@ func (tx *txFake) QueryContext(ctx context.Context, query string, args []driver.
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return rows, nil
}
@@ -113,8 +116,8 @@ func (tx *txFake) ExecContext(ctx context.Context, query string, args []driver.N
) {
onDone := trace.DatabaseSQLOnTxExec(
tx.conn.trace, &ctx,
- stack.FunctionID(""),
- tx.ctx, tx, query, xcontext.IsIdempotent(ctx),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).ExecContext"),
+ tx.ctx, tx, query,
)
defer func() {
onDone(err)
@@ -123,5 +126,6 @@ func (tx *txFake) ExecContext(ctx context.Context, query string, args []driver.N
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return result, nil
}
diff --git a/internal/xsql/unwrap.go b/internal/xsql/unwrap.go
index 39755e50e..5f54b0252 100644
--- a/internal/xsql/unwrap.go
+++ b/internal/xsql/unwrap.go
@@ -15,17 +15,21 @@ func Unwrap[T *sql.DB | *sql.Conn](v T) (connector *Connector, err error) {
if dw, ok := d.(*driverWrapper); ok {
return dw.c, nil
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf("%T is not a *driverWrapper", d))
case *sql.Conn:
if err = vv.Raw(func(driverConn interface{}) error {
if cc, ok := driverConn.(*conn); ok {
connector = cc.connector
+
return nil
}
+
return xerrors.WithStackTrace(fmt.Errorf("%T is not a *conn", driverConn))
}); err != nil {
return nil, badconn.Map(xerrors.WithStackTrace(err))
}
+
return connector, nil
default:
return nil, xerrors.WithStackTrace(fmt.Errorf("unknown type %T for Unwrap", vv))
diff --git a/internal/xsql/valuer.go b/internal/xsql/valuer.go
index 750d52819..6171908b1 100644
--- a/internal/xsql/valuer.go
+++ b/internal/xsql/valuer.go
@@ -1,13 +1,16 @@
package xsql
-import "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
+import (
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/scanner"
+)
type valuer struct {
v interface{}
}
-func (v *valuer) UnmarshalYDB(raw types.RawValue) error {
+func (v *valuer) UnmarshalYDB(raw scanner.RawValue) error {
v.v = raw.Any()
+
return nil
}
diff --git a/internal/xstring/convert.go b/internal/xstring/convert.go
index 7881a16cb..eb7ee4b05 100644
--- a/internal/xstring/convert.go
+++ b/internal/xstring/convert.go
@@ -11,6 +11,7 @@ func FromBytes(b []byte) string {
if len(b) == 0 {
return ""
}
+
return unsafe.String(&b[0], len(b))
}
@@ -18,5 +19,6 @@ func ToBytes(s string) (b []byte) {
if s == "" {
return nil
}
+
return unsafe.Slice(unsafe.StringData(s), len(s))
}
diff --git a/internal/xsync/event_broadcast_test.go b/internal/xsync/event_broadcast_test.go
index c52d57bf7..93a8860b7 100644
--- a/internal/xsync/event_broadcast_test.go
+++ b/internal/xsync/event_broadcast_test.go
@@ -2,13 +2,13 @@ package xsync
import (
"runtime"
+ "sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
)
@@ -24,12 +24,12 @@ func TestEventBroadcast(t *testing.T) {
testDuration := time.Second / 100
b := &EventBroadcast{}
- var events xatomic.Int64
+ var events atomic.Int64
- var backgroundCounter xatomic.Int64
- firstWaiterStarted := xatomic.Bool{}
+ var backgroundCounter atomic.Int64
+ firstWaiterStarted := atomic.Bool{}
- stopSubscribe := xatomic.Bool{}
+ stopSubscribe := atomic.Bool{}
subscribeStopped := make(empty.Chan)
broadcastStopped := make(empty.Chan)
@@ -51,7 +51,7 @@ func TestEventBroadcast(t *testing.T) {
}
}()
- stopBroadcast := xatomic.Bool{}
+ stopBroadcast := atomic.Bool{}
go func() {
defer close(broadcastStopped)
diff --git a/internal/xsync/once.go b/internal/xsync/once.go
new file mode 100644
index 000000000..35f5ed0aa
--- /dev/null
+++ b/internal/xsync/once.go
@@ -0,0 +1,61 @@
+package xsync
+
+import (
+ "context"
+ "sync"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
+)
+
+func OnceFunc(f func(ctx context.Context) error) func(ctx context.Context) error {
+ var once sync.Once
+
+ return func(ctx context.Context) (err error) {
+ once.Do(func() {
+ err = f(ctx)
+ })
+
+ return err
+ }
+}
+
+type Once[T closer.Closer] struct {
+ f func() T
+ once sync.Once
+ mutex sync.RWMutex
+ t T
+}
+
+func OnceValue[T closer.Closer](f func() T) *Once[T] {
+ return &Once[T]{f: f}
+}
+
+func (v *Once[T]) Close(ctx context.Context) (err error) {
+ has := true
+ v.once.Do(func() {
+ has = false
+ })
+
+ if has {
+ v.mutex.RLock()
+ defer v.mutex.RUnlock()
+
+ return v.t.Close(ctx)
+ }
+
+ return nil
+}
+
+func (v *Once[T]) Get() T {
+ v.once.Do(func() {
+ v.mutex.Lock()
+ defer v.mutex.Unlock()
+
+ v.t = v.f()
+ })
+
+ v.mutex.RLock()
+ defer v.mutex.RUnlock()
+
+ return v.t
+}
diff --git a/internal/xsync/once_test.go b/internal/xsync/once_test.go
new file mode 100644
index 000000000..003e9a7e7
--- /dev/null
+++ b/internal/xsync/once_test.go
@@ -0,0 +1,93 @@
+package xsync
+
+import (
+ "context"
+ "errors"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestOnceFunc(t *testing.T) {
+ var (
+ ctx = xtest.Context(t)
+ cnt = 0
+ )
+ f := OnceFunc(func(ctx context.Context) error {
+ cnt++
+
+ return nil
+ })
+ require.Equal(t, 0, cnt)
+ require.NoError(t, f(ctx))
+ require.Equal(t, 1, cnt)
+ require.NoError(t, f(ctx))
+ require.Equal(t, 1, cnt)
+}
+
+type testCloser struct {
+ value int
+ inited bool
+ closed bool
+ closeErr error
+}
+
+func (c *testCloser) Close(ctx context.Context) error {
+ c.closed = true
+
+ return c.closeErr
+}
+
+func TestOnceValue(t *testing.T) {
+ ctx := xtest.Context(t)
+ t.Run("Race", func(t *testing.T) {
+ counter := 0
+ once := OnceValue(func() *testCloser {
+ counter++
+
+ return &testCloser{value: counter}
+ })
+ var wg sync.WaitGroup
+ wg.Add(1000)
+ for range make([]struct{}, 1000) {
+ go func() {
+ defer wg.Done()
+ v := once.Get()
+ require.Equal(t, 1, v.value)
+ }()
+ }
+ wg.Wait()
+ })
+ t.Run("GetBeforeClose", func(t *testing.T) {
+ constCloseErr := errors.New("")
+ once := OnceValue(func() *testCloser {
+ return &testCloser{
+ inited: true,
+ closeErr: constCloseErr,
+ }
+ })
+ v := once.Get()
+ require.True(t, v.inited)
+ require.False(t, v.closed)
+ err := once.Close(ctx)
+ require.ErrorIs(t, err, constCloseErr)
+ require.True(t, v.inited)
+ require.True(t, v.closed)
+ })
+ t.Run("CloseBeforeGet", func(t *testing.T) {
+ constCloseErr := errors.New("")
+ once := OnceValue(func() *testCloser {
+ return &testCloser{
+ inited: true,
+ closeErr: constCloseErr,
+ }
+ })
+ err := once.Close(ctx)
+ require.NoError(t, err)
+ v := once.Get()
+ require.Nil(t, v)
+ })
+}
diff --git a/internal/xtest/call_method.go b/internal/xtest/call_method.go
new file mode 100644
index 000000000..a7e060a8a
--- /dev/null
+++ b/internal/xtest/call_method.go
@@ -0,0 +1,25 @@
+package xtest
+
+import (
+ "reflect"
+)
+
+func CallMethod(object any, name string, args ...any) []any {
+ method := reflect.ValueOf(object).MethodByName(name)
+
+ inputs := make([]reflect.Value, len(args))
+
+ for i := range args {
+ inputs[i] = reflect.ValueOf(args[i])
+ }
+
+ output := method.Call(inputs)
+
+ result := make([]any, len(output))
+
+ for i := range output {
+ result[i] = output[i].Interface()
+ }
+
+ return result
+}
diff --git a/internal/xtest/call_method_test.go b/internal/xtest/call_method_test.go
new file mode 100644
index 000000000..fe721761d
--- /dev/null
+++ b/internal/xtest/call_method_test.go
@@ -0,0 +1,39 @@
+package xtest
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestCallMethod(t *testing.T) {
+ object := bytes.NewBuffer(nil)
+
+ result := CallMethod(object, "WriteString", "Hello world!")
+ n := result[0].(int)
+ err := result[1]
+
+ require.Equal(t, 12, n)
+ require.Nil(t, err)
+
+ result = CallMethod(object, "String")
+
+ str, ok := result[0].(string)
+ require.True(t, ok)
+
+ require.Equal(t, object.String(), str)
+
+ require.Panics(t, func() {
+ CallMethod(object, "NonameMethod")
+ })
+
+ require.Panics(t, func() {
+ CallMethod(object, "String", "wrong", "arguments", "count")
+ })
+
+ require.Panics(t, func() {
+ // Wrong argument type.
+ CallMethod(object, "WriteString", 123)
+ })
+}
diff --git a/internal/xtest/context.go b/internal/xtest/context.go
index 38cd0b73b..318cac0ba 100644
--- a/internal/xtest/context.go
+++ b/internal/xtest/context.go
@@ -17,6 +17,7 @@ func Context(t testing.TB) context.Context {
pprof.SetGoroutineLabels(ctx)
cancel()
})
+
return ctx
}
@@ -27,5 +28,6 @@ func ContextWithCommonTimeout(ctx context.Context, t testing.TB) context.Context
ctx, ctxCancel := xcontext.WithTimeout(ctx, commonWaitTimeout)
_ = ctxCancel // suppress linters, it is ok for leak for small amount of time: it will cancel by parent context
+
return ctx
}
diff --git a/internal/xtest/grpclogger.go b/internal/xtest/grpclogger.go
index f42ddcc90..3506d4ccb 100644
--- a/internal/xtest/grpclogger.go
+++ b/internal/xtest/grpclogger.go
@@ -16,7 +16,7 @@ var globalLastStreamID = int64(0)
//
// db, err := ydb.Open(context.Background(), connectionString,
// ...
-// ydb.With(config.WithGrpcOptions(grpc.WithChainUnaryInterceptor(xtest.NewGrpcLogger(t).UnaryClientInterceptor))),
+// ydb.Change(config.WithGrpcOptions(grpc.WithChainUnaryInterceptor(xtest.NewGrpcLogger(t).UnaryClientInterceptor))),
// )
type GrpcLogger struct {
t testing.TB
@@ -42,6 +42,7 @@ func (l GrpcLogger) UnaryClientInterceptor(
req,
reply,
)
+
return err
}
@@ -64,6 +65,7 @@ func (l GrpcLogger) StreamClientInterceptor(
err,
streamWrapper.streamID,
)
+
return stream, err
}
@@ -80,17 +82,20 @@ func newGrpcLoggerStream(stream grpc.ClientStream, t testing.TB) grpcLoggerStrea
func (g grpcLoggerStream) CloseSend() error {
err := g.ClientStream.CloseSend()
g.t.Logf("CloseSend: %v (streamID: %v)", err, g.streamID)
+
return err
}
func (g grpcLoggerStream) SendMsg(m interface{}) error {
err := g.ClientStream.SendMsg(m)
g.t.Logf("SendMsg (streamID: %v) with err '%v':\n%v ", g.streamID, err, m)
+
return err
}
func (g grpcLoggerStream) RecvMsg(m interface{}) error {
err := g.ClientStream.RecvMsg(m)
g.t.Logf("RecvMsg (streamID: %v) with err '%v':\n%v ", g.streamID, err, m)
+
return err
}
diff --git a/internal/xtest/manytimes.go b/internal/xtest/manytimes.go
index cd84603fb..4dc7f1ccb 100644
--- a/internal/xtest/manytimes.go
+++ b/internal/xtest/manytimes.go
@@ -31,9 +31,9 @@ func TestManyTimes(t testing.TB, test TestFunc, opts ...TestManyTimesOption) {
stopAfter: time.Second,
}
- for _, o := range opts {
- if o != nil {
- o(&options)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&options)
}
}
diff --git a/internal/xtest/waiters.go b/internal/xtest/waiters.go
index 1f09cb7f7..34389c1c0 100644
--- a/internal/xtest/waiters.go
+++ b/internal/xtest/waiters.go
@@ -64,6 +64,7 @@ func SpinWaitConditionWithTimeout(tb testing.TB, l sync.Locker, condWaitTimeout
l.Lock()
defer l.Unlock()
}
+
return cond()
}
@@ -102,6 +103,7 @@ func SpinWaitProgressWithTimeout(
SpinWaitConditionWithTimeout(tb, nil, timeout, func() bool {
progressValue, finished := progress()
+
return finished || progressValue != currentValue
})
}
diff --git a/internal/xtest/ydb_grpc_mocks.go b/internal/xtest/ydb_grpc_mocks.go
new file mode 100644
index 000000000..d3816feca
--- /dev/null
+++ b/internal/xtest/ydb_grpc_mocks.go
@@ -0,0 +1,140 @@
+package xtest
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "reflect"
+ "strconv"
+ "time"
+
+ "github.com/rekby/fixenv"
+ "github.com/rekby/fixenv/sf"
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Discovery_V1"
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Topic_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Discovery"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations"
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/types/known/anypb"
+)
+
+func GrpcMockTopicConnString(e fixenv.Env, topicServiceImpl Ydb_Topic_V1.TopicServiceServer) string {
+ v := reflect.ValueOf(topicServiceImpl)
+ addr := v.Pointer()
+
+ var f fixenv.GenericFixtureFunction[string] = func() (*fixenv.GenericResult[string], error) {
+ listener := sf.LocalTCPListenerNamed(e, fmt.Sprintf("ydb-grpc-mock-topic-%v", addr))
+ connString := fmt.Sprintf("grpc://%s/local", listener.Addr())
+
+ mock, err := newGrpcMock(listener, topicServiceImpl)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create grpc mock: %w", err)
+ }
+
+ clean := func() {
+ _ = mock.Close()
+ }
+
+ return fixenv.NewGenericResultWithCleanup(connString, clean), nil
+ }
+
+ return fixenv.CacheResult(e, f, fixenv.CacheOptions{CacheKey: addr})
+}
+
+type grpcMock struct {
+ listener net.Listener
+ grpcServer *grpc.Server
+ stopChan chan error
+}
+
+func (m *grpcMock) Close() error {
+ m.grpcServer.Stop()
+
+ return m.listener.Close()
+}
+
+func newGrpcMock(listener net.Listener, topicServiceImpl Ydb_Topic_V1.TopicServiceServer) (*grpcMock, error) {
+ res := &grpcMock{
+ listener: listener,
+ grpcServer: grpc.NewServer(),
+ stopChan: make(chan error, 1),
+ }
+
+ host, portS, err := net.SplitHostPort(listener.Addr().String())
+ if err != nil {
+ return nil, fmt.Errorf("failed to split host port addresses: %w", err)
+ }
+
+ port, err := strconv.ParseUint(portS, 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("failed convert port to int: %w", err)
+ }
+ discoveryService := newMockDiscoveryService(host, uint32(port))
+
+ Ydb_Discovery_V1.RegisterDiscoveryServiceServer(res.grpcServer, discoveryService)
+ Ydb_Topic_V1.RegisterTopicServiceServer(res.grpcServer, topicServiceImpl)
+
+ go func() {
+ res.stopChan <- res.grpcServer.Serve(res.listener)
+ }()
+
+ select {
+ case <-res.stopChan:
+ return nil, err
+ case <-time.After(time.Millisecond):
+ return res, nil
+ }
+}
+
+type mockDiscoveryService struct {
+ Ydb_Discovery_V1.UnimplementedDiscoveryServiceServer
+ host string
+ port uint32
+}
+
+func newMockDiscoveryService(host string, port uint32) *mockDiscoveryService {
+ return &mockDiscoveryService{
+ host: host,
+ port: port,
+ }
+}
+
+func (m mockDiscoveryService) ListEndpoints(
+ ctx context.Context,
+ request *Ydb_Discovery.ListEndpointsRequest,
+) (*Ydb_Discovery.ListEndpointsResponse, error) {
+ res := &Ydb_Discovery.ListEndpointsResult{
+ Endpoints: []*Ydb_Discovery.EndpointInfo{
+ {
+ Address: m.host,
+ Port: m.port,
+ LoadFactor: 0,
+ Ssl: false,
+ Service: nil,
+ Location: "",
+ NodeId: 1,
+ IpV4: []string{"127.0.0.1"},
+ },
+ },
+ SelfLocation: "",
+ }
+ resp := &Ydb_Discovery.ListEndpointsResponse{
+ Operation: &Ydb_Operations.Operation{
+ Id: "test-list-operation",
+ Ready: true,
+ Status: Ydb.StatusIds_SUCCESS,
+ Result: &anypb.Any{},
+ },
+ }
+ err := resp.GetOperation().GetResult().MarshalFrom(res)
+
+ return resp, err
+}
+
+func (m mockDiscoveryService) WhoAmI(
+ ctx context.Context,
+ request *Ydb_Discovery.WhoAmIRequest,
+) (*Ydb_Discovery.WhoAmIResponse, error) {
+ panic("unimplemented")
+}
diff --git a/log/context.go b/log/context.go
index f376f47ce..81231df01 100644
--- a/log/context.go
+++ b/log/context.go
@@ -13,6 +13,7 @@ func WithLevel(ctx context.Context, lvl Level) context.Context {
func LevelFromContext(ctx context.Context) Level {
v, _ := ctx.Value(ctxLevelKey{}).(Level)
+
return v
}
@@ -25,6 +26,7 @@ func NamesFromContext(ctx context.Context) []string {
if v == nil {
return []string{}
}
+
return v
}
diff --git a/log/discovery.go b/log/discovery.go
index f9b7c60d5..452c61876 100644
--- a/log/discovery.go
+++ b/log/discovery.go
@@ -11,7 +11,7 @@ func Discovery(l Logger, d trace.Detailer, opts ...Option) (t trace.Discovery) {
return internalDiscovery(wrapLogger(l, opts...), d)
}
-func internalDiscovery(l *wrapper, d trace.Detailer) (t trace.Discovery) {
+func internalDiscovery(l Logger, d trace.Detailer) (t trace.Discovery) {
t.OnDiscover = func(info trace.DiscoveryDiscoverStartInfo) func(trace.DiscoveryDiscoverDoneInfo) {
if d.Details()&trace.DiscoveryEvents == 0 {
return nil
@@ -22,6 +22,7 @@ func internalDiscovery(l *wrapper, d trace.Detailer) (t trace.Discovery) {
String("database", info.Database),
)
start := time.Now()
+
return func(info trace.DiscoveryDiscoverDoneInfo) {
if info.Error == nil {
l.Log(WithLevel(ctx, INFO), "done",
@@ -44,6 +45,7 @@ func internalDiscovery(l *wrapper, d trace.Detailer) (t trace.Discovery) {
ctx := with(*info.Context, TRACE, "ydb", "discovery", "whoAmI")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DiscoveryWhoAmIDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -60,5 +62,6 @@ func internalDiscovery(l *wrapper, d trace.Detailer) (t trace.Discovery) {
}
}
}
+
return t
}
diff --git a/log/driver.go b/log/driver.go
index 8292f31bc..fb9c8b1a1 100644
--- a/log/driver.go
+++ b/log/driver.go
@@ -13,257 +13,185 @@ func Driver(l Logger, d trace.Detailer, opts ...Option) (t trace.Driver) {
return internalDriver(wrapLogger(l, opts...), d)
}
-func internalDriver(l *wrapper, d trace.Detailer) (t trace.Driver) { //nolint:gocyclo
- t.OnResolve = func(
- info trace.DriverResolveStartInfo,
- ) func(
- trace.DriverResolveDoneInfo,
- ) {
- if d.Details()&trace.DriverResolverEvents == 0 {
- return nil
- }
- ctx := with(context.Background(), TRACE, "ydb", "driver", "resolver", "update")
- target := info.Target
- addresses := info.Resolved
- l.Log(ctx, "start",
- String("target", target),
- Strings("resolved", addresses),
- )
- return func(info trace.DriverResolveDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- String("target", target),
- Strings("resolved", addresses),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- String("target", target),
- Strings("resolved", addresses),
- versionField(),
- )
+func internalDriver(l Logger, d trace.Detailer) trace.Driver { //nolint:gocyclo
+ return trace.Driver{
+ OnResolve: func(
+ info trace.DriverResolveStartInfo,
+ ) func(
+ trace.DriverResolveDoneInfo,
+ ) {
+ if d.Details()&trace.DriverResolverEvents == 0 {
+ return nil
}
- }
- }
- t.OnInit = func(info trace.DriverInitStartInfo) func(trace.DriverInitDoneInfo) {
- if d.Details()&trace.DriverEvents == 0 {
- return nil
- }
- endpoint := info.Endpoint
- database := info.Database
- secure := info.Secure
- ctx := with(*info.Context, DEBUG, "ydb", "driver", "resolver", "init")
- l.Log(ctx, "start",
- String("endpoint", endpoint),
- String("database", database),
- Bool("secure", secure),
- )
- start := time.Now()
- return func(info trace.DriverInitDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- String("endpoint", endpoint),
- String("database", database),
- Bool("secure", secure),
- latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- Error(info.Error),
- String("endpoint", endpoint),
- String("database", database),
- Bool("secure", secure),
- latencyField(start),
- versionField(),
- )
+ ctx := with(context.Background(), TRACE, "ydb", "driver", "resolver", "update")
+ target := info.Target
+ addresses := info.Resolved
+ l.Log(ctx, "start",
+ String("target", target),
+ Strings("resolved", addresses),
+ )
+
+ return func(info trace.DriverResolveDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ String("target", target),
+ Strings("resolved", addresses),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ String("target", target),
+ Strings("resolved", addresses),
+ versionField(),
+ )
+ }
}
- }
- }
- t.OnClose = func(info trace.DriverCloseStartInfo) func(trace.DriverCloseDoneInfo) {
- if d.Details()&trace.DriverEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "resolver", "close")
- l.Log(ctx, "start")
- start := time.Now()
- return func(info trace.DriverCloseDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- latencyField(start),
- versionField(),
- )
+ },
+ OnInit: func(info trace.DriverInitStartInfo) func(trace.DriverInitDoneInfo) {
+ if d.Details()&trace.DriverEvents == 0 {
+ return nil
}
- }
- }
- t.OnConnDial = func(info trace.DriverConnDialStartInfo) func(trace.DriverConnDialDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "dial")
- endpoint := info.Endpoint
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- )
- start := time.Now()
- return func(info trace.DriverConnDialDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- Stringer("endpoint", endpoint),
- latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- Stringer("endpoint", endpoint),
- latencyField(start),
- versionField(),
- )
+ endpoint := info.Endpoint
+ database := info.Database
+ secure := info.Secure
+ ctx := with(*info.Context, DEBUG, "ydb", "driver", "resolver", "init")
+ l.Log(ctx, "start",
+ String("endpoint", endpoint),
+ String("database", database),
+ Bool("secure", secure),
+ )
+ start := time.Now()
+
+ return func(info trace.DriverInitDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ String("endpoint", endpoint),
+ String("database", database),
+ Bool("secure", secure),
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ Error(info.Error),
+ String("endpoint", endpoint),
+ String("database", database),
+ Bool("secure", secure),
+ latencyField(start),
+ versionField(),
+ )
+ }
}
- }
- }
- t.OnConnStateChange = func(info trace.DriverConnStateChangeStartInfo) func(trace.DriverConnStateChangeDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(context.Background(), TRACE, "ydb", "driver", "conn", "state", "change")
- endpoint := info.Endpoint
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- Stringer("state", info.State),
- )
- start := time.Now()
- return func(info trace.DriverConnStateChangeDoneInfo) {
- l.Log(ctx, "done",
+ },
+ OnClose: func(info trace.DriverCloseStartInfo) func(trace.DriverCloseDoneInfo) {
+ if d.Details()&trace.DriverEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "resolver", "close")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnConnDial: func(info trace.DriverConnDialStartInfo) func(trace.DriverConnDialDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "dial")
+ endpoint := info.Endpoint
+ l.Log(ctx, "start",
+ Stringer("endpoint", endpoint),
+ )
+ start := time.Now()
+
+ return func(info trace.DriverConnDialDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ Stringer("endpoint", endpoint),
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ Stringer("endpoint", endpoint),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnConnStateChange: func(info trace.DriverConnStateChangeStartInfo) func(trace.DriverConnStateChangeDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "driver", "conn", "state", "change")
+ endpoint := info.Endpoint
+ l.Log(ctx, "start",
Stringer("endpoint", endpoint),
- latencyField(start),
Stringer("state", info.State),
)
- }
- }
- t.OnConnPark = func(info trace.DriverConnParkStartInfo) func(trace.DriverConnParkDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "park")
- endpoint := info.Endpoint
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- )
- start := time.Now()
- return func(info trace.DriverConnParkDoneInfo) {
- if info.Error == nil {
+ start := time.Now()
+
+ return func(info trace.DriverConnStateChangeDoneInfo) {
l.Log(ctx, "done",
Stringer("endpoint", endpoint),
latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- Stringer("endpoint", endpoint),
- latencyField(start),
- versionField(),
+ Stringer("state", info.State),
)
}
- }
- }
- t.OnConnClose = func(info trace.DriverConnCloseStartInfo) func(trace.DriverConnCloseDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "close")
- endpoint := info.Endpoint
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- )
- start := time.Now()
- return func(info trace.DriverConnCloseDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- Stringer("endpoint", endpoint),
- latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- Stringer("endpoint", endpoint),
- latencyField(start),
- versionField(),
- )
+ },
+ OnConnClose: func(info trace.DriverConnCloseStartInfo) func(trace.DriverConnCloseDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
}
- }
- }
- t.OnConnInvoke = func(info trace.DriverConnInvokeStartInfo) func(trace.DriverConnInvokeDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "invoke")
- endpoint := info.Endpoint
- method := string(info.Method)
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- String("method", method),
- )
- start := time.Now()
- return func(info trace.DriverConnInvokeDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- Stringer("endpoint", endpoint),
- String("method", method),
- latencyField(start),
- Stringer("metadata", metadata(info.Metadata)),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- Stringer("endpoint", endpoint),
- String("method", method),
- latencyField(start),
- Stringer("metadata", metadata(info.Metadata)),
- versionField(),
- )
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "close")
+ endpoint := info.Endpoint
+ l.Log(ctx, "start",
+ Stringer("endpoint", endpoint),
+ )
+ start := time.Now()
+
+ return func(info trace.DriverConnCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ Stringer("endpoint", endpoint),
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ Stringer("endpoint", endpoint),
+ latencyField(start),
+ versionField(),
+ )
+ }
}
- }
- }
- t.OnConnNewStream = func(
- info trace.DriverConnNewStreamStartInfo,
- ) func(
- trace.DriverConnNewStreamRecvInfo,
- ) func(
- trace.DriverConnNewStreamDoneInfo,
- ) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "new", "stream")
- endpoint := info.Endpoint
- method := string(info.Method)
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- String("method", method),
- )
- start := time.Now()
- return func(info trace.DriverConnNewStreamRecvInfo) func(trace.DriverConnNewStreamDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "intermediate receive",
- Stringer("endpoint", endpoint),
- String("method", method),
- latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "intermediate fail",
- Error(info.Error),
- Stringer("endpoint", endpoint),
- String("method", method),
- latencyField(start),
- versionField(),
- )
+ },
+ OnConnInvoke: func(info trace.DriverConnInvokeStartInfo) func(trace.DriverConnInvokeDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
}
- return func(info trace.DriverConnNewStreamDoneInfo) {
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "invoke")
+ endpoint := info.Endpoint
+ method := string(info.Method)
+ l.Log(ctx, "start",
+ Stringer("endpoint", endpoint),
+ String("method", method),
+ )
+ start := time.Now()
+
+ return func(info trace.DriverConnInvokeDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
Stringer("endpoint", endpoint),
@@ -282,182 +210,293 @@ func internalDriver(l *wrapper, d trace.Detailer) (t trace.Driver) { //nolint:go
)
}
}
- }
- }
- t.OnConnBan = func(info trace.DriverConnBanStartInfo) func(trace.DriverConnBanDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "ban")
- endpoint := info.Endpoint
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- NamedError("cause", info.Cause),
- versionField(),
- )
- start := time.Now()
- return func(info trace.DriverConnBanDoneInfo) {
- l.Log(WithLevel(ctx, WARN), "done",
+ },
+ OnConnNewStream: func(
+ info trace.DriverConnNewStreamStartInfo,
+ ) func(
+ trace.DriverConnNewStreamDoneInfo,
+ ) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "stream", "New")
+ endpoint := info.Endpoint
+ method := string(info.Method)
+ l.Log(ctx, "start",
Stringer("endpoint", endpoint),
- latencyField(start),
- Stringer("state", info.State),
- versionField(),
+ String("method", method),
)
- }
- }
- t.OnConnAllow = func(info trace.DriverConnAllowStartInfo) func(trace.DriverConnAllowDoneInfo) {
- if d.Details()&trace.DriverConnEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "allow")
- endpoint := info.Endpoint
- l.Log(ctx, "start",
- Stringer("endpoint", endpoint),
- )
- start := time.Now()
- return func(info trace.DriverConnAllowDoneInfo) {
- l.Log(ctx, "done",
+ start := time.Now()
+
+ return func(info trace.DriverConnNewStreamDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ Stringer("endpoint", endpoint),
+ String("method", method),
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ Stringer("endpoint", endpoint),
+ String("method", method),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnConnStreamCloseSend: func(info trace.DriverConnStreamCloseSendStartInfo) func(
+ trace.DriverConnStreamCloseSendDoneInfo,
+ ) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "stream", "CloseSend")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverConnStreamCloseSendDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnConnStreamSendMsg: func(info trace.DriverConnStreamSendMsgStartInfo) func(trace.DriverConnStreamSendMsgDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "stream", "SendMsg")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverConnStreamSendMsgDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnConnStreamRecvMsg: func(info trace.DriverConnStreamRecvMsgStartInfo) func(trace.DriverConnStreamRecvMsgDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "stream", "RecvMsg")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverConnStreamRecvMsgDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnConnBan: func(info trace.DriverConnBanStartInfo) func(trace.DriverConnBanDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "ban")
+ endpoint := info.Endpoint
+ cause := info.Cause
+ l.Log(ctx, "start",
Stringer("endpoint", endpoint),
- latencyField(start),
- Stringer("state", info.State),
+ NamedError("cause", cause),
)
- }
- }
- t.OnRepeaterWakeUp = func(info trace.DriverRepeaterWakeUpStartInfo) func(trace.DriverRepeaterWakeUpDoneInfo) {
- if d.Details()&trace.DriverRepeaterEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "repeater", "wake", "up")
- name := info.Name
- event := info.Event
- l.Log(ctx, "start",
- String("name", name),
- String("event", event),
- )
- start := time.Now()
- return func(info trace.DriverRepeaterWakeUpDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- String("name", name),
- String("event", event),
- latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- Error(info.Error),
- String("name", name),
- String("event", event),
+ start := time.Now()
+
+ return func(info trace.DriverConnBanDoneInfo) {
+ l.Log(WithLevel(ctx, WARN), "done",
+ Stringer("endpoint", endpoint),
latencyField(start),
+ Stringer("state", info.State),
+ NamedError("cause", cause),
versionField(),
)
}
- }
- }
- t.OnBalancerInit = func(info trace.DriverBalancerInitStartInfo) func(trace.DriverBalancerInitDoneInfo) {
- if d.Details()&trace.DriverBalancerEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "init")
- l.Log(ctx, "start")
- start := time.Now()
- return func(info trace.DriverBalancerInitDoneInfo) {
- l.Log(WithLevel(ctx, INFO), "done",
- latencyField(start),
+ },
+ OnConnAllow: func(info trace.DriverConnAllowStartInfo) func(trace.DriverConnAllowDoneInfo) {
+ if d.Details()&trace.DriverConnEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "conn", "allow")
+ endpoint := info.Endpoint
+ l.Log(ctx, "start",
+ Stringer("endpoint", endpoint),
)
- }
- }
- t.OnBalancerClose = func(info trace.DriverBalancerCloseStartInfo) func(trace.DriverBalancerCloseDoneInfo) {
- if d.Details()&trace.DriverBalancerEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "close")
- l.Log(ctx, "start")
- start := time.Now()
- return func(info trace.DriverBalancerCloseDoneInfo) {
- if info.Error == nil {
+ start := time.Now()
+
+ return func(info trace.DriverConnAllowDoneInfo) {
l.Log(ctx, "done",
+ Stringer("endpoint", endpoint),
latencyField(start),
- )
- } else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- latencyField(start),
- versionField(),
+ Stringer("state", info.State),
)
}
- }
- }
- t.OnBalancerChooseEndpoint = func(
- info trace.DriverBalancerChooseEndpointStartInfo,
- ) func(
- trace.DriverBalancerChooseEndpointDoneInfo,
- ) {
- if d.Details()&trace.DriverBalancerEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "choose", "endpoint")
- l.Log(ctx, "start")
- start := time.Now()
- return func(info trace.DriverBalancerChooseEndpointDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Stringer("endpoint", info.Endpoint),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- Error(info.Error),
+ },
+ OnRepeaterWakeUp: func(info trace.DriverRepeaterWakeUpStartInfo) func(trace.DriverRepeaterWakeUpDoneInfo) {
+ if d.Details()&trace.DriverRepeaterEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "repeater", "wake", "up")
+ name := info.Name
+ event := info.Event
+ l.Log(ctx, "start",
+ String("name", name),
+ String("event", event),
+ )
+ start := time.Now()
+
+ return func(info trace.DriverRepeaterWakeUpDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ String("name", name),
+ String("event", event),
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ Error(info.Error),
+ String("name", name),
+ String("event", event),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnBalancerInit: func(info trace.DriverBalancerInitStartInfo) func(trace.DriverBalancerInitDoneInfo) {
+ if d.Details()&trace.DriverBalancerEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "init")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverBalancerInitDoneInfo) {
+ l.Log(WithLevel(ctx, INFO), "done",
latencyField(start),
- versionField(),
)
}
- }
- }
- t.OnBalancerUpdate = func(
- info trace.DriverBalancerUpdateStartInfo,
- ) func(
- trace.DriverBalancerUpdateDoneInfo,
- ) {
- if d.Details()&trace.DriverBalancerEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "update")
- l.Log(ctx, "start",
- Bool("needLocalDC", info.NeedLocalDC),
- )
- start := time.Now()
- return func(info trace.DriverBalancerUpdateDoneInfo) {
- l.Log(ctx, "done",
- latencyField(start),
- Stringer("endpoints", endpoints(info.Endpoints)),
- Stringer("added", endpoints(info.Added)),
- Stringer("dropped", endpoints(info.Dropped)),
- String("detectedLocalDC", info.LocalDC),
+ },
+ OnBalancerClose: func(info trace.DriverBalancerCloseStartInfo) func(trace.DriverBalancerCloseDoneInfo) {
+ if d.Details()&trace.DriverBalancerEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "close")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverBalancerCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, WARN), "failed",
+ Error(info.Error),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnBalancerChooseEndpoint: func(
+ info trace.DriverBalancerChooseEndpointStartInfo,
+ ) func(
+ trace.DriverBalancerChooseEndpointDoneInfo,
+ ) {
+ if d.Details()&trace.DriverBalancerEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "choose", "endpoint")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverBalancerChooseEndpointDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Stringer("endpoint", info.Endpoint),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ Error(info.Error),
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnBalancerUpdate: func(
+ info trace.DriverBalancerUpdateStartInfo,
+ ) func(
+ trace.DriverBalancerUpdateDoneInfo,
+ ) {
+ if d.Details()&trace.DriverBalancerEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "balancer", "update")
+ l.Log(ctx, "start",
+ Bool("needLocalDC", info.NeedLocalDC),
)
- }
- }
- t.OnGetCredentials = func(info trace.DriverGetCredentialsStartInfo) func(trace.DriverGetCredentialsDoneInfo) {
- if d.Details()&trace.DriverCredentialsEvents == 0 {
- return nil
- }
- ctx := with(*info.Context, TRACE, "ydb", "driver", "credentials", "get")
- l.Log(ctx, "start")
- start := time.Now()
- return func(info trace.DriverGetCredentialsDoneInfo) {
- if info.Error == nil {
+ start := time.Now()
+
+ return func(info trace.DriverBalancerUpdateDoneInfo) {
l.Log(ctx, "done",
latencyField(start),
- String("token", secret.Token(info.Token)),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "done",
- Error(info.Error),
- latencyField(start),
- String("token", secret.Token(info.Token)),
- versionField(),
+ Stringer("endpoints", endpoints(info.Endpoints)),
+ Stringer("added", endpoints(info.Added)),
+ Stringer("dropped", endpoints(info.Dropped)),
+ String("detectedLocalDC", info.LocalDC),
)
}
- }
+ },
+ OnGetCredentials: func(info trace.DriverGetCredentialsStartInfo) func(trace.DriverGetCredentialsDoneInfo) {
+ if d.Details()&trace.DriverCredentialsEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "driver", "credentials", "get")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.DriverGetCredentialsDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ String("token", secret.Token(info.Token)),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "done",
+ Error(info.Error),
+ latencyField(start),
+ String("token", secret.Token(info.Token)),
+ versionField(),
+ )
+ }
+ }
+ },
}
- return t
}
diff --git a/log/field.go b/log/field.go
index 605064987..af6f65598 100644
--- a/log/field.go
+++ b/log/field.go
@@ -51,30 +51,35 @@ func (f Field) Key() string {
// StringValue is a value getter for fields with StringType type
func (f Field) StringValue() string {
f.checkType(StringType)
+
return f.vstr
}
// IntValue is a value getter for fields with IntType type
func (f Field) IntValue() int {
f.checkType(IntType)
+
return int(f.vint)
}
// Int64Value is a value getter for fields with Int64Type type
func (f Field) Int64Value() int64 {
f.checkType(Int64Type)
+
return f.vint
}
// BoolValue is a value getter for fields with BoolType type
func (f Field) BoolValue() bool {
f.checkType(BoolType)
+
return f.vint != 0
}
// DurationValue is a value getter for fields with DurationType type
func (f Field) DurationValue() time.Duration {
f.checkType(DurationType)
+
return time.Nanosecond * time.Duration(f.vint)
}
@@ -84,6 +89,7 @@ func (f Field) StringsValue() []string {
if f.vany == nil {
return nil
}
+
return f.vany.([]string)
}
@@ -93,6 +99,7 @@ func (f Field) ErrorValue() error {
if f.vany == nil {
return nil
}
+
return f.vany.(error)
}
@@ -128,6 +135,7 @@ func (f Field) Stringer() fmt.Stringer {
if f.vany == nil {
return nil
}
+
return f.vany.(fmt.Stringer)
}
@@ -156,6 +164,7 @@ func (f Field) String() string {
if f.vany == nil || f.vany.(error) == nil {
return ""
}
+
return f.ErrorValue().Error()
case AnyType:
if f.vany == nil {
@@ -165,8 +174,10 @@ func (f Field) String() string {
if v.IsNil() {
return nilPtr
}
+
return v.Type().String() + "(" + fmt.Sprint(v.Elem()) + ")"
}
+
return fmt.Sprint(f.vany)
case StringerType:
return f.Stringer().String()
@@ -209,6 +220,7 @@ func Bool(key string, value bool) Field {
} else {
vint = 0
}
+
return Field{
ftype: BoolType,
key: key,
@@ -263,6 +275,7 @@ func Stringer(key string, value fmt.Stringer) Field {
if value == nil {
return Any(key, nil)
}
+
return Field{
ftype: StringerType,
key: key,
@@ -327,6 +340,7 @@ func (ft FieldType) String() (typeName string) {
default:
panic("not implemented")
}
+
return typeName
}
@@ -353,6 +367,7 @@ func (ee endpoints) String() string {
b.WriteString(e.String())
}
b.WriteByte(']')
+
return b.String()
}
@@ -363,6 +378,7 @@ func (m metadata) String() string {
if err != nil {
return fmt.Sprintf("error:%s", err)
}
+
return xstring.FromBytes(b)
}
@@ -370,5 +386,6 @@ func appendFieldByCondition(condition bool, ifTrueField Field, fields ...Field)
if condition {
fields = append(fields, ifTrueField)
}
+
return fields
}
diff --git a/log/field_test.go b/log/field_test.go
index 73b3f8e49..af2dfb217 100644
--- a/log/field_test.go
+++ b/log/field_test.go
@@ -48,11 +48,13 @@ func TestField_String(t *testing.T) {
// Known fieldType, but String() panics with it.
if tt.panic {
require.Panics(t, func() { _ = tt.f.String() })
+
return
}
// Unknown fieldType, maybe a new one has been added
if tt.fail {
t.Fail()
+
return
}
require.Equal(t, tt.want, tt.f.String())
diff --git a/log/logger.go b/log/logger.go
index c5391180a..8caf7229a 100644
--- a/log/logger.go
+++ b/log/logger.go
@@ -33,17 +33,20 @@ func Default(w io.Writer, opts ...simpleLoggerOption) *defaultLogger {
clock: clockwork.NewRealClock(),
w: w,
}
- for _, o := range opts {
- o.applySimpleOption(l)
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applySimpleOption(l)
+ }
}
+
return l
}
type defaultLogger struct {
coloring bool
- clock clockwork.Clock
logQuery bool
minLevel Level
+ clock clockwork.Clock
w io.Writer
}
@@ -77,6 +80,7 @@ func (l *defaultLogger) format(namespace []string, msg string, logLevel Level) s
if l.coloring {
b.WriteString(colorReset)
}
+
return b.String()
}
@@ -102,11 +106,12 @@ func wrapLogger(l Logger, opts ...Option) *wrapper {
ll := &wrapper{
logger: l,
}
- for _, o := range opts {
- if o != nil {
- o.applyHolderOption(ll)
+ for _, opt := range opts {
+ if opt != nil {
+ opt.applyHolderOption(ll)
}
}
+
return ll
}
@@ -125,6 +130,7 @@ func (l *defaultLogger) appendFields(msg string, fields ...Field) string {
fmt.Fprintf(b, `%q:%q`, fields[i].Key(), fields[i].String())
}
b.WriteByte('}')
+
return b.String()
}
diff --git a/log/query.go b/log/query.go
new file mode 100644
index 000000000..e44e9e3ac
--- /dev/null
+++ b/log/query.go
@@ -0,0 +1,653 @@
+package log
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+// Query makes trace.Query with logging events from details
+func Query(l Logger, d trace.Detailer, opts ...Option) (t trace.Query) {
+ return internalQuery(wrapLogger(l, opts...), d)
+}
+
+//nolint:gocyclo
+func internalQuery(
+ l *wrapper, //nolint:interfacer
+ d trace.Detailer,
+) trace.Query {
+ return trace.Query{
+ OnNew: func(info trace.QueryNewStartInfo) func(info trace.QueryNewDoneInfo) {
+ if d.Details()&trace.QueryEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "new")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryNewDoneInfo) {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ }
+ },
+ OnClose: func(info trace.QueryCloseStartInfo) func(info trace.QueryCloseDoneInfo) {
+ if d.Details()&trace.QueryEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "close")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnPoolNew: func(info trace.QueryPoolNewStartInfo) func(trace.QueryPoolNewDoneInfo) {
+ if d.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "pool", "new")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryPoolNewDoneInfo) {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ Int("Limit", info.Limit),
+ )
+ }
+ },
+ OnPoolClose: func(info trace.QueryPoolCloseStartInfo) func(trace.QueryPoolCloseDoneInfo) {
+ if d.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "pool", "close")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryPoolCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnPoolTry: func(info trace.QueryPoolTryStartInfo) func(trace.QueryPoolTryDoneInfo) {
+ if d.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "pool", "try")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryPoolTryDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnPoolWith: func(info trace.QueryPoolWithStartInfo) func(trace.QueryPoolWithDoneInfo) {
+ if d.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, DEBUG, "ydb", "query", "pool", "with")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryPoolWithDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Int("Attempts", info.Attempts),
+ )
+ } else {
+ lvl := ERROR
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ Int("Attempts", info.Attempts),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnPoolPut: func(info trace.QueryPoolPutStartInfo) func(trace.QueryPoolPutDoneInfo) {
+ if d.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "pool", "put")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryPoolPutDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnPoolGet: func(info trace.QueryPoolGetStartInfo) func(trace.QueryPoolGetDoneInfo) {
+ if d.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "pool", "get")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryPoolGetDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnDo: func(info trace.QueryDoStartInfo) func(trace.QueryDoDoneInfo) {
+ if d.Details()&trace.QueryEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "do")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryDoDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Int("attempts", info.Attempts),
+ )
+ } else {
+ lvl := ERROR
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ Int("attempts", info.Attempts),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnDoTx: func(info trace.QueryDoTxStartInfo) func(trace.QueryDoTxDoneInfo) {
+ if d.Details()&trace.QueryEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "do", "tx")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryDoTxDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Int("attempts", info.Attempts),
+ )
+ } else {
+ lvl := ERROR
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ Int("attempts", info.Attempts),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnSessionCreate: func(info trace.QuerySessionCreateStartInfo) func(info trace.QuerySessionCreateDoneInfo) {
+ if d.Details()&trace.QuerySessionEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "session", "create")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QuerySessionCreateDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ String("session_id", info.Session.ID()),
+ String("session_status", info.Session.Status()),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "done",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnSessionAttach: func(info trace.QuerySessionAttachStartInfo) func(info trace.QuerySessionAttachDoneInfo) {
+ if d.Details()&trace.QuerySessionEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "session", "attach")
+ l.Log(ctx, "start",
+ String("session_id", info.Session.ID()),
+ String("session_status", info.Session.Status()),
+ )
+ start := time.Now()
+
+ return func(info trace.QuerySessionAttachDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnSessionDelete: func(info trace.QuerySessionDeleteStartInfo) func(info trace.QuerySessionDeleteDoneInfo) {
+ if d.Details()&trace.QuerySessionEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "session", "delete")
+ l.Log(ctx, "start",
+ String("session_id", info.Session.ID()),
+ String("session_status", info.Session.Status()),
+ )
+ start := time.Now()
+
+ return func(info trace.QuerySessionDeleteDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnSessionExecute: func(info trace.QuerySessionExecuteStartInfo) func(info trace.QuerySessionExecuteDoneInfo) {
+ if d.Details()&trace.QuerySessionEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "session", "execute")
+ l.Log(ctx, "start",
+ String("SessionID", info.Session.ID()),
+ String("SessionStatus", info.Session.Status()),
+ String("Query", info.Query),
+ )
+ start := time.Now()
+
+ return func(info trace.QuerySessionExecuteDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnSessionBegin: func(info trace.QuerySessionBeginStartInfo) func(info trace.QuerySessionBeginDoneInfo) {
+ if d.Details()&trace.QuerySessionEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "session", "begin")
+ l.Log(ctx, "start",
+ String("SessionID", info.Session.ID()),
+ String("SessionStatus", info.Session.Status()),
+ )
+ start := time.Now()
+
+ return func(info trace.QuerySessionBeginDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, DEBUG), "done",
+ latencyField(start),
+ String("TransactionID", info.Tx.ID()),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnTxExecute: func(info trace.QueryTxExecuteStartInfo) func(info trace.QueryTxExecuteDoneInfo) {
+ if d.Details()&trace.QueryTransactionEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "transaction", "execute")
+ l.Log(ctx, "start",
+ String("SessionID", info.Session.ID()),
+ String("TransactionID", info.Tx.ID()),
+ String("SessionStatus", info.Session.Status()),
+ )
+ start := time.Now()
+
+ return func(info trace.QueryTxExecuteDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, DEBUG), "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnResultNew: func(info trace.QueryResultNewStartInfo) func(info trace.QueryResultNewDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "result", "new")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryResultNewDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnResultNextPart: func(info trace.QueryResultNextPartStartInfo) func(info trace.QueryResultNextPartDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "result", "next", "part")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryResultNextPartDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnResultNextResultSet: func(
+ info trace.QueryResultNextResultSetStartInfo,
+ ) func(
+ info trace.QueryResultNextResultSetDoneInfo,
+ ) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "result", "next", "result", "set")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryResultNextResultSetDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnResultClose: func(info trace.QueryResultCloseStartInfo) func(info trace.QueryResultCloseDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "result", "close")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryResultCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnResultSetNextRow: func(info trace.QueryResultSetNextRowStartInfo) func(info trace.QueryResultSetNextRowDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "result", "set", "next", "row")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryResultSetNextRowDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnRowScan: func(info trace.QueryRowScanStartInfo) func(info trace.QueryRowScanDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "row", "scan")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryRowScanDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnRowScanNamed: func(info trace.QueryRowScanNamedStartInfo) func(info trace.QueryRowScanNamedDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "row", "scan", "named")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryRowScanNamedDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnRowScanStruct: func(info trace.QueryRowScanStructStartInfo) func(info trace.QueryRowScanStructDoneInfo) {
+ if d.Details()&trace.QueryResultEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "query", "row", "scan", "struct")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.QueryRowScanStructDoneInfo) {
+ if info.Error == nil {
+ l.Log(ctx, "done",
+ latencyField(start),
+ )
+ } else {
+ lvl := WARN
+ if !xerrors.IsYdb(info.Error) {
+ lvl = DEBUG
+ }
+ l.Log(WithLevel(ctx, lvl), "failed",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ }
+ },
+ }
+}
diff --git a/log/retry.go b/log/retry.go
index 4f0c582b6..df772bdb3 100644
--- a/log/retry.go
+++ b/log/retry.go
@@ -13,14 +13,8 @@ func Retry(l Logger, d trace.Detailer, opts ...Option) (t trace.Retry) {
return internalRetry(wrapLogger(l, opts...), d)
}
-func internalRetry(l *wrapper, d trace.Detailer) (t trace.Retry) {
- t.OnRetry = func(
- info trace.RetryLoopStartInfo,
- ) func(
- trace.RetryLoopIntermediateInfo,
- ) func(
- trace.RetryLoopDoneInfo,
- ) {
+func internalRetry(l Logger, d trace.Detailer) (t trace.Retry) {
+ t.OnRetry = func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
if d.Details()&trace.RetryEvents == 0 {
return nil
}
@@ -32,11 +26,13 @@ func internalRetry(l *wrapper, d trace.Detailer) (t trace.Retry) {
Bool("idempotent", idempotent),
)
start := time.Now()
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+
+ return func(info trace.RetryLoopDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "attempt done",
+ l.Log(ctx, "done",
String("label", label),
latencyField(start),
+ Int("attempts", info.Attempts),
)
} else {
lvl := ERROR
@@ -44,42 +40,19 @@ func internalRetry(l *wrapper, d trace.Detailer) (t trace.Retry) {
lvl = DEBUG
}
m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "attempt failed",
+ l.Log(WithLevel(ctx, lvl), "failed",
Error(info.Error),
String("label", label),
latencyField(start),
+ Int("attempts", info.Attempts),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
versionField(),
)
}
- return func(info trace.RetryLoopDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- String("label", label),
- latencyField(start),
- Int("attempts", info.Attempts),
- )
- } else {
- lvl := ERROR
- if !xerrors.IsYdb(info.Error) {
- lvl = DEBUG
- }
- m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "failed",
- Error(info.Error),
- String("label", label),
- latencyField(start),
- Int("attempts", info.Attempts),
- Bool("retryable", m.MustRetry(idempotent)),
- Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
- versionField(),
- )
- }
- }
}
}
+
return t
}
diff --git a/log/scripting.go b/log/scripting.go
index 6d45d60a1..4af256cb1 100644
--- a/log/scripting.go
+++ b/log/scripting.go
@@ -19,6 +19,7 @@ func internalScripting(l *wrapper, d trace.Detailer) (t trace.Scripting) {
ctx := with(*info.Context, TRACE, "ydb", "scripting", "execute")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.ScriptingExecuteDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -42,6 +43,7 @@ func internalScripting(l *wrapper, d trace.Detailer) (t trace.Scripting) {
ctx := with(*info.Context, TRACE, "ydb", "scripting", "explain")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.ScriptingExplainDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -75,6 +77,7 @@ func internalScripting(l *wrapper, d trace.Detailer) (t trace.Scripting) {
)...,
)
start := time.Now()
+
return func(
info trace.ScriptingStreamExecuteIntermediateInfo,
) func(
@@ -88,6 +91,7 @@ func internalScripting(l *wrapper, d trace.Detailer) (t trace.Scripting) {
versionField(),
)
}
+
return func(info trace.ScriptingStreamExecuteDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -116,6 +120,7 @@ func internalScripting(l *wrapper, d trace.Detailer) (t trace.Scripting) {
ctx := with(*info.Context, TRACE, "ydb", "scripting", "close")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.ScriptingCloseDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -130,5 +135,6 @@ func internalScripting(l *wrapper, d trace.Detailer) (t trace.Scripting) {
}
}
}
+
return t
}
diff --git a/log/sql.go b/log/sql.go
index a89994b37..5ef2a56f3 100644
--- a/log/sql.go
+++ b/log/sql.go
@@ -25,6 +25,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(*info.Context, TRACE, "ydb", "database", "sql", "connector", "connect")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLConnectorConnectDoneInfo) {
if info.Error == nil {
l.Log(WithLevel(ctx, DEBUG), "connected",
@@ -49,6 +50,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(*info.Context, TRACE, "ydb", "database", "sql", "conn", "ping")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLConnPingDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -70,6 +72,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(context.Background(), TRACE, "ydb", "database", "sql", "conn", "close")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLConnCloseDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -91,6 +94,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(*info.Context, TRACE, "ydb", "database", "sql", "conn", "begin", "tx")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLConnBeginDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -117,6 +121,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
)
query := info.Query
start := time.Now()
+
return func(info trace.DatabaseSQLConnPrepareDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -147,6 +152,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
query := info.Query
idempotent := info.Idempotent
start := time.Now()
+
return func(info trace.DatabaseSQLConnExecDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -159,7 +165,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
String("query", query),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
Error(info.Error),
latencyField(start),
versionField(),
@@ -181,6 +187,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
query := info.Query
idempotent := info.Idempotent
start := time.Now()
+
return func(info trace.DatabaseSQLConnQueryDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -193,7 +200,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
String("query", query),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
Error(info.Error),
latencyField(start),
versionField(),
@@ -209,6 +216,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(*info.Context, TRACE, "ydb", "database", "sql", "tx", "commit")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLTxCommitDoneInfo) {
if info.Error == nil {
l.Log(ctx, "committed",
@@ -230,6 +238,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(*info.Context, TRACE, "ydb", "database", "sql", "tx", "rollback")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLTxRollbackDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -251,6 +260,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
ctx := with(context.Background(), TRACE, "ydb", "database", "sql", "stmt", "close")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.DatabaseSQLStmtCloseDoneInfo) {
if info.Error == nil {
l.Log(ctx, "closed",
@@ -277,6 +287,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
)
query := info.Query
start := time.Now()
+
return func(info trace.DatabaseSQLStmtExecDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -307,6 +318,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
)
query := info.Query
start := time.Now()
+
return func(info trace.DatabaseSQLStmtQueryDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -324,5 +336,6 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
}
}
}
+
return t
}
diff --git a/log/table.go b/log/table.go
index 0570dcbf1..c12dd30ad 100644
--- a/log/table.go
+++ b/log/table.go
@@ -18,8 +18,6 @@ func Table(l Logger, d trace.Detailer, opts ...Option) (t trace.Table) {
func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
t.OnDo = func(
info trace.TableDoStartInfo,
- ) func(
- info trace.TableDoIntermediateInfo,
) func(
trace.TableDoDoneInfo,
) {
@@ -34,63 +32,37 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("label", label),
)
start := time.Now()
- return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
+
+ return func(info trace.TableDoDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
)
} else {
- lvl := WARN
+ lvl := ERROR
if !xerrors.IsYdb(info.Error) {
lvl = DEBUG
}
m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "failed",
+ l.Log(WithLevel(ctx, lvl), "done",
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
Error(info.Error),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
versionField(),
)
}
- return func(info trace.TableDoDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- )
- } else {
- lvl := ERROR
- if !xerrors.IsYdb(info.Error) {
- lvl = DEBUG
- }
- m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- Error(info.Error),
- Bool("retryable", m.MustRetry(idempotent)),
- Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
- versionField(),
- )
- }
- }
}
}
t.OnDoTx = func(
info trace.TableDoTxStartInfo,
- ) func(
- info trace.TableDoTxIntermediateInfo,
) func(
trace.TableDoTxDoneInfo,
) {
@@ -105,15 +77,17 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("label", label),
)
start := time.Now()
- return func(info trace.TableDoTxIntermediateInfo) func(trace.TableDoTxDoneInfo) {
+
+ return func(info trace.TableDoTxDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
)
} else {
- lvl := ERROR
+ lvl := WARN
if !xerrors.IsYdb(info.Error) {
lvl = DEBUG
}
@@ -122,46 +96,18 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
Error(info.Error),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
versionField(),
)
}
- return func(info trace.TableDoTxDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- )
- } else {
- lvl := WARN
- if !xerrors.IsYdb(info.Error) {
- lvl = DEBUG
- }
- m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- Error(info.Error),
- Bool("retryable", m.MustRetry(idempotent)),
- Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
- versionField(),
- )
- }
- }
}
}
t.OnCreateSession = func(
info trace.TableCreateSessionStartInfo,
- ) func(
- info trace.TableCreateSessionIntermediateInfo,
) func(
trace.TableCreateSessionDoneInfo,
) {
@@ -171,35 +117,23 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
ctx := with(*info.Context, TRACE, "ydb", "table", "create", "session")
l.Log(ctx, "start")
start := time.Now()
- return func(info trace.TableCreateSessionIntermediateInfo) func(trace.TableCreateSessionDoneInfo) {
+
+ return func(info trace.TableCreateSessionDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "intermediate",
+ l.Log(ctx, "done",
latencyField(start),
+ Int("attempts", info.Attempts),
+ String("session_id", info.Session.ID()),
+ String("session_status", info.Session.Status()),
)
} else {
- l.Log(WithLevel(ctx, ERROR), "intermediate",
+ l.Log(WithLevel(ctx, ERROR), "failed",
latencyField(start),
+ Int("attempts", info.Attempts),
Error(info.Error),
versionField(),
)
}
- return func(info trace.TableCreateSessionDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Int("attempts", info.Attempts),
- String("session_id", info.Session.ID()),
- String("session_status", info.Session.Status()),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- latencyField(start),
- Int("attempts", info.Attempts),
- Error(info.Error),
- versionField(),
- )
- }
- }
}
}
t.OnSessionNew = func(info trace.TableSessionNewStartInfo) func(trace.TableSessionNewDoneInfo) {
@@ -209,6 +143,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
ctx := with(*info.Context, TRACE, "ydb", "table", "session", "new")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.TableSessionNewDoneInfo) {
if info.Error == nil {
if info.Session != nil {
@@ -242,6 +177,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("status", info.Session.Status()),
)
start := time.Now()
+
return func(info trace.TableSessionDeleteDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -271,6 +207,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("status", session.Status()),
)
start := time.Now()
+
return func(info trace.TableKeepAliveDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -308,6 +245,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)...,
)
start := time.Now()
+
return func(info trace.TablePrepareDataQueryDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -354,6 +292,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)...,
)
start := time.Now()
+
return func(info trace.TableExecuteDataQueryDoneInfo) {
if info.Error == nil {
tx := info.Tx
@@ -385,8 +324,6 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
t.OnSessionQueryStreamExecute = func(
info trace.TableSessionQueryStreamExecuteStartInfo,
- ) func(
- trace.TableSessionQueryStreamExecuteIntermediateInfo,
) func(
trace.TableSessionQueryStreamExecuteDoneInfo,
) {
@@ -404,49 +341,34 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)...,
)
start := time.Now()
- return func(
- info trace.TableSessionQueryStreamExecuteIntermediateInfo,
- ) func(
- trace.TableSessionQueryStreamExecuteDoneInfo,
- ) {
+
+ return func(info trace.TableSessionQueryStreamExecuteDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "intermediate")
+ l.Log(ctx, "done",
+ appendFieldByCondition(l.logQuery,
+ Stringer("query", query),
+ Error(info.Error),
+ String("id", session.ID()),
+ String("status", session.Status()),
+ latencyField(start),
+ )...,
+ )
} else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- versionField(),
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ appendFieldByCondition(l.logQuery,
+ Stringer("query", query),
+ Error(info.Error),
+ String("id", session.ID()),
+ String("status", session.Status()),
+ latencyField(start),
+ versionField(),
+ )...,
)
}
- return func(info trace.TableSessionQueryStreamExecuteDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- appendFieldByCondition(l.logQuery,
- Stringer("query", query),
- Error(info.Error),
- String("id", session.ID()),
- String("status", session.Status()),
- latencyField(start),
- )...,
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- appendFieldByCondition(l.logQuery,
- Stringer("query", query),
- Error(info.Error),
- String("id", session.ID()),
- String("status", session.Status()),
- latencyField(start),
- versionField(),
- )...,
- )
- }
- }
}
}
t.OnSessionQueryStreamRead = func(
info trace.TableSessionQueryStreamReadStartInfo,
- ) func(
- intermediateInfo trace.TableSessionQueryStreamReadIntermediateInfo,
) func(
trace.TableSessionQueryStreamReadDoneInfo,
) {
@@ -460,42 +382,29 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("status", session.Status()),
)
start := time.Now()
- return func(
- info trace.TableSessionQueryStreamReadIntermediateInfo,
- ) func(
- trace.TableSessionQueryStreamReadDoneInfo,
- ) {
+
+ return func(info trace.TableSessionQueryStreamReadDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "intermediate")
+ l.Log(ctx, "done",
+ latencyField(start),
+ String("id", session.ID()),
+ String("status", session.Status()),
+ )
} else {
- l.Log(WithLevel(ctx, WARN), "failed",
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ latencyField(start),
+ String("id", session.ID()),
+ String("status", session.Status()),
Error(info.Error),
versionField(),
)
}
- return func(info trace.TableSessionQueryStreamReadDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- String("id", session.ID()),
- String("status", session.Status()),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- latencyField(start),
- String("id", session.ID()),
- String("status", session.Status()),
- Error(info.Error),
- versionField(),
- )
- }
- }
}
}
- t.OnSessionTransactionBegin = func(
- info trace.TableSessionTransactionBeginStartInfo,
+ t.OnTxBegin = func(
+ info trace.TableTxBeginStartInfo,
) func(
- trace.TableSessionTransactionBeginDoneInfo,
+ trace.TableTxBeginDoneInfo,
) {
if d.Details()&trace.TableSessionTransactionEvents == 0 {
return nil
@@ -507,7 +416,8 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("status", session.Status()),
)
start := time.Now()
- return func(info trace.TableSessionTransactionBeginDoneInfo) {
+
+ return func(info trace.TableTxBeginDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
@@ -526,11 +436,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
}
}
- t.OnSessionTransactionCommit = func(
- info trace.TableSessionTransactionCommitStartInfo,
- ) func(
- trace.TableSessionTransactionCommitDoneInfo,
- ) {
+ t.OnTxCommit = func(info trace.TableTxCommitStartInfo) func(trace.TableTxCommitDoneInfo) {
if d.Details()&trace.TableSessionTransactionEvents == 0 {
return nil
}
@@ -543,7 +449,8 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("tx", info.Tx.ID()),
)
start := time.Now()
- return func(info trace.TableSessionTransactionCommitDoneInfo) {
+
+ return func(info trace.TableTxCommitDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
@@ -563,10 +470,10 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
}
}
- t.OnSessionTransactionRollback = func(
- info trace.TableSessionTransactionRollbackStartInfo,
+ t.OnTxRollback = func(
+ info trace.TableTxRollbackStartInfo,
) func(
- trace.TableSessionTransactionRollbackDoneInfo,
+ trace.TableTxRollbackDoneInfo,
) {
if d.Details()&trace.TableSessionTransactionEvents == 0 {
return nil
@@ -580,7 +487,8 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("tx", tx.ID()),
)
start := time.Now()
- return func(info trace.TableSessionTransactionRollbackDoneInfo) {
+
+ return func(info trace.TableTxRollbackDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
@@ -607,6 +515,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
ctx := with(*info.Context, TRACE, "ydb", "table", "init")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.TableInitDoneInfo) {
l.Log(WithLevel(ctx, INFO), "done",
latencyField(start),
@@ -621,6 +530,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
ctx := with(*info.Context, TRACE, "ydb", "table", "close")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.TableCloseDoneInfo) {
if info.Error == nil {
l.Log(WithLevel(ctx, INFO), "done",
@@ -676,6 +586,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
String("status", session.Status()),
)
start := time.Now()
+
return func(info trace.TablePoolPutDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
@@ -701,6 +612,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
ctx := with(*info.Context, TRACE, "ydb", "table", "pool", "get")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.TablePoolGetDoneInfo) {
if info.Error == nil {
session := info.Session
@@ -727,6 +639,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
ctx := with(*info.Context, TRACE, "ydb", "table", "pool", "wait")
l.Log(ctx, "start")
start := time.Now()
+
return func(info trace.TablePoolWaitDoneInfo) {
fields := []Field{
latencyField(start),
@@ -745,5 +658,6 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
}
}
+
return t
}
diff --git a/log/topic.go b/log/topic.go
index 769d081f0..87d645d9b 100644
--- a/log/topic.go
+++ b/log/topic.go
@@ -12,7 +12,7 @@ func Topic(l Logger, d trace.Detailer, opts ...Option) (t trace.Topic) {
return internalTopic(wrapLogger(l, opts...), d)
}
-func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocyclo
+func internalTopic(l Logger, d trace.Detailer) (t trace.Topic) { //nolint:gocyclo
t.OnReaderReconnect = func(
info trace.TopicReaderReconnectStartInfo,
) func(doneInfo trace.TopicReaderReconnectDoneInfo) {
@@ -22,6 +22,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
ctx := with(context.Background(), TRACE, "ydb", "topic", "reader", "reconnect")
start := time.Now()
l.Log(ctx, "start")
+
return func(doneInfo trace.TopicReaderReconnectDoneInfo) {
l.Log(WithLevel(ctx, INFO), "reconnected",
NamedError("reason", info.Reason),
@@ -53,6 +54,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int64("partition_id", info.PartitionID),
Int64("partition_session_id", info.PartitionSessionID),
)
+
return func(doneInfo trace.TopicReaderPartitionReadStartResponseDoneInfo) {
fields := []Field{
String("topic", info.Topic),
@@ -98,6 +100,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int64("partition_session_id", info.PartitionSessionID),
Int64("committed_offset", info.CommittedOffset),
Bool("graceful", info.Graceful))
+
return func(doneInfo trace.TopicReaderPartitionReadStopResponseDoneInfo) {
fields := []Field{
String("reader_connection_id", info.ReaderConnectionID),
@@ -133,6 +136,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int64("commit_start_offset", info.StartOffset),
Int64("commit_end_offset", info.EndOffset),
)
+
return func(doneInfo trace.TopicReaderCommitDoneInfo) {
fields := []Field{
String("topic", info.Topic),
@@ -173,6 +177,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int64("commit_end_offset", commitInfo[i].EndOffset),
)
}
+
return func(doneInfo trace.TopicReaderSendCommitMessageDoneInfo) {
for i := range commitInfo {
fields := []Field{
@@ -219,6 +224,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
String("reader_connection_id", info.ReaderConnectionID),
NamedError("close_reason", info.CloseReason),
)
+
return func(doneInfo trace.TopicReaderCloseDoneInfo) {
fields := []Field{
String("reader_connection_id", info.ReaderConnectionID),
@@ -248,6 +254,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
String("consumer", info.InitRequestInfo.GetConsumer()),
Strings("topics", info.InitRequestInfo.GetTopics()),
)
+
return func(doneInfo trace.TopicReaderInitDoneInfo) {
fields := []Field{
String("pre_init_reader_connection_id", info.PreInitReaderConnectionID),
@@ -291,6 +298,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
l.Log(ctx, "token updating...",
String("reader_connection_id", info.ReaderConnectionID),
)
+
return func(
updateTokenInfo trace.OnReadUpdateTokenMiddleTokenReceivedInfo,
) func(doneInfo trace.OnReadStreamUpdateTokenDoneInfo) {
@@ -309,6 +317,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
versionField(),
)
}
+
return func(doneInfo trace.OnReadStreamUpdateTokenDoneInfo) {
if doneInfo.Error == nil {
l.Log(ctx, "token updated on stream",
@@ -356,6 +365,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int("batches_count", batchesCount),
Int("messages_count", messagesCount),
)
+
return func(doneInfo trace.TopicReaderReceiveDataResponseDoneInfo) {
if doneInfo.Error == nil {
l.Log(ctx, "data response received and processed",
@@ -395,6 +405,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int("max_count", info.MaxCount),
Int("local_capacity_before", info.FreeBufferCapacity),
)
+
return func(doneInfo trace.TopicReaderReadMessagesDoneInfo) {
if doneInfo.Error == nil {
l.Log(ctx, "read messages returned",
@@ -443,6 +454,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
String("writer_instance_id", info.WriterInstanceID),
Int("attempt", info.Attempt),
)
+
return func(doneInfo trace.TopicWriterReconnectDoneInfo) {
if doneInfo.Error == nil {
l.Log(WithLevel(ctx, DEBUG), "connect to topic writer stream completed",
@@ -510,6 +522,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
String("writer_instance_id", info.WriterInstanceID),
NamedError("reason", info.Reason),
)
+
return func(doneInfo trace.TopicWriterCloseDoneInfo) {
if doneInfo.Error == nil {
l.Log(WithLevel(ctx, DEBUG), "close topic writer completed",
@@ -544,6 +557,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int("messages_count", info.MessagesCount),
Int64("first_seqno", info.FirstSeqNo),
)
+
return func(doneInfo trace.TopicWriterCompressMessagesDoneInfo) {
if doneInfo.Error == nil {
l.Log(ctx, "compress message completed",
@@ -585,6 +599,7 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
Int("messages_count", info.MessagesCount),
Int64("first_seqno", info.FirstSeqNo),
)
+
return func(doneInfo trace.TopicWriterSendMessagesDoneInfo) {
if doneInfo.Error == nil {
l.Log(ctx, "send messages completed",
@@ -619,5 +634,6 @@ func internalTopic(l *wrapper, d trace.Detailer) (t trace.Topic) { //nolint:gocy
String("session_id", info.SessionID),
)
}
+
return t
}
diff --git a/meta/consumed_units.go b/meta/consumed_units.go
index 48f89b7b2..ea4617962 100644
--- a/meta/consumed_units.go
+++ b/meta/consumed_units.go
@@ -20,5 +20,6 @@ func ConsumedUnits(md metadata.MD) (consumedUnits uint64) {
}
}
}
+
return consumedUnits
}
diff --git a/meta/context.go b/meta/context.go
index b2f95b5be..5ea200db6 100644
--- a/meta/context.go
+++ b/meta/context.go
@@ -14,8 +14,15 @@ func WithTraceID(ctx context.Context, traceID string) context.Context {
}
// WithUserAgent returns a copy of parent context with custom user-agent info
-func WithUserAgent(ctx context.Context, userAgent string) context.Context {
- return meta.WithUserAgent(ctx, userAgent)
+//
+// Deprecated: use WithApplicationName instead
+func WithUserAgent(ctx context.Context, _ string) context.Context {
+ return ctx
+}
+
+// WithApplicationName returns a copy of parent context with application name
+func WithApplicationName(ctx context.Context, applicationName string) context.Context {
+ return meta.WithApplicationName(ctx, applicationName)
}
// WithRequestType returns a copy of parent context with custom request type
@@ -25,7 +32,7 @@ func WithRequestType(ctx context.Context, requestType string) context.Context {
// WithAllowFeatures returns a copy of parent context with allowed client feature
func WithAllowFeatures(ctx context.Context, features ...string) context.Context {
- return meta.WithAllowFeatures(ctx, features)
+ return meta.WithAllowFeatures(ctx, features...)
}
// WithTrailerCallback attaches callback to context for listening incoming metadata
diff --git a/meta/example_test.go b/meta/example_test.go
index 50a5af4ae..97ae1e67b 100644
--- a/meta/example_test.go
+++ b/meta/example_test.go
@@ -48,6 +48,7 @@ func Example_consumedUnitsCount() {
}
log.Printf("id=%v, myStr='%s'\n", id, myStr)
}
+
return res.Err() // return finally result error for auto-retry with driver
},
table.WithIdempotent(),
diff --git a/metrics/driver.go b/metrics/driver.go
index 257c2d4e4..5b2f12fbc 100644
--- a/metrics/driver.go
+++ b/metrics/driver.go
@@ -31,6 +31,7 @@ func driver(config Config) (t trace.Driver) {
endpoint = info.Endpoint.Address()
nodeID = info.Endpoint.NodeID()
)
+
return func(info trace.DriverConnInvokeDoneInfo) {
if config.Details()&trace.DriverConnEvents != 0 {
requests.With(map[string]string{
@@ -46,8 +47,6 @@ func driver(config Config) (t trace.Driver) {
}
}
t.OnConnNewStream = func(info trace.DriverConnNewStreamStartInfo) func(
- trace.DriverConnNewStreamRecvInfo,
- ) func(
trace.DriverConnNewStreamDoneInfo,
) {
var (
@@ -55,16 +54,15 @@ func driver(config Config) (t trace.Driver) {
endpoint = info.Endpoint.Address()
nodeID = info.Endpoint.NodeID()
)
- return func(info trace.DriverConnNewStreamRecvInfo) func(trace.DriverConnNewStreamDoneInfo) {
- return func(info trace.DriverConnNewStreamDoneInfo) {
- if config.Details()&trace.DriverConnEvents != 0 {
- requests.With(map[string]string{
- "status": errorBrief(info.Error),
- "method": string(method),
- "endpoint": endpoint,
- "node_id": strconv.FormatUint(uint64(nodeID), 10),
- }).Inc()
- }
+
+ return func(info trace.DriverConnNewStreamDoneInfo) {
+ if config.Details()&trace.DriverConnEvents != 0 {
+ requests.With(map[string]string{
+ "status": errorBrief(info.Error),
+ "method": string(method),
+ "endpoint": endpoint,
+ "node_id": strconv.FormatUint(uint64(nodeID), 10),
+ }).Inc()
}
}
}
@@ -76,12 +74,14 @@ func driver(config Config) (t trace.Driver) {
"cause": errorBrief(info.Cause),
}).Add(1)
}
+
return nil
}
t.OnBalancerClusterDiscoveryAttempt = func(info trace.DriverBalancerClusterDiscoveryAttemptStartInfo) func(
trace.DriverBalancerClusterDiscoveryAttemptDoneInfo,
) {
eventType := repeater.EventType(*info.Context)
+
return func(info trace.DriverBalancerClusterDiscoveryAttemptDoneInfo) {
balancersDiscoveries.With(map[string]string{
"status": errorBrief(info.Error),
@@ -91,6 +91,7 @@ func driver(config Config) (t trace.Driver) {
}
t.OnBalancerUpdate = func(info trace.DriverBalancerUpdateStartInfo) func(trace.DriverBalancerUpdateDoneInfo) {
eventType := repeater.EventType(*info.Context)
+
return func(info trace.DriverBalancerUpdateDoneInfo) {
if config.Details()&trace.DriverBalancerEvents != 0 {
balancerUpdates.With(map[string]string{
@@ -126,6 +127,7 @@ func driver(config Config) (t trace.Driver) {
t.OnConnDial = func(info trace.DriverConnDialStartInfo) func(trace.DriverConnDialDoneInfo) {
endpoint := info.Endpoint.Address()
nodeID := info.Endpoint.NodeID()
+
return func(info trace.DriverConnDialDoneInfo) {
if config.Details()&trace.DriverConnEvents != 0 {
if info.Error == nil {
@@ -144,7 +146,9 @@ func driver(config Config) (t trace.Driver) {
"node_id": idToString(info.Endpoint.NodeID()),
}).Add(-1)
}
+
return nil
}
+
return t
}
diff --git a/metrics/error_brief.go b/metrics/error_brief.go
index d7fd0e8f2..241687da5 100644
--- a/metrics/error_brief.go
+++ b/metrics/error_brief.go
@@ -34,6 +34,7 @@ func errorBrief(err error) string {
buffer.WriteString(errorBrief(netErr.Err))
buffer.WriteByte(')')
}
+
return buffer.String()
}
if xerrors.Is(err, context.DeadlineExceeded) {
@@ -54,5 +55,6 @@ func errorBrief(err error) string {
if ydbErr := xerrors.Error(nil); xerrors.As(err, &ydbErr) {
return ydbErr.Name()
}
+
return "unknown"
}
diff --git a/metrics/query.go b/metrics/query.go
new file mode 100644
index 000000000..2d48cfd52
--- /dev/null
+++ b/metrics/query.go
@@ -0,0 +1,210 @@
+package metrics
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+func query(config Config) (t trace.Query) {
+ queryConfig := config.WithSystem("query")
+ {
+ poolConfig := queryConfig.WithSystem("pool")
+ {
+ withConfig := poolConfig.WithSystem("with")
+ errs := withConfig.CounterVec("errs", "status")
+ latency := withConfig.TimerVec("latency")
+ attempts := withConfig.HistogramVec("attempts", []float64{0, 1, 2, 3, 4, 5, 7, 10})
+ t.OnPoolWith = func(
+ info trace.QueryPoolWithStartInfo,
+ ) func(
+ info trace.QueryPoolWithDoneInfo,
+ ) {
+ if withConfig.Details()&trace.QueryPoolEvents == 0 {
+ return nil
+ }
+
+ start := time.Now()
+
+ return func(info trace.QueryPoolWithDoneInfo) {
+ attempts.With(nil).Record(float64(info.Attempts))
+ if info.Error != nil {
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ }
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ {
+ sizeConfig := poolConfig.WithSystem("size")
+ limit := sizeConfig.GaugeVec("limit")
+ idle := sizeConfig.GaugeVec("idle")
+ index := sizeConfig.GaugeVec("index")
+ inUse := sizeConfig.WithSystem("in").GaugeVec("use")
+
+ t.OnPoolChange = func(stats trace.QueryPoolChange) {
+ if sizeConfig.Details()&trace.QueryPoolEvents == 0 {
+ return
+ }
+
+ limit.With(nil).Set(float64(stats.Limit))
+ idle.With(nil).Set(float64(stats.Idle))
+ inUse.With(nil).Set(float64(stats.InUse))
+ index.With(nil).Set(float64(stats.Index))
+ }
+ }
+ }
+ {
+ doConfig := queryConfig.WithSystem("do")
+ {
+ errs := doConfig.CounterVec("errs", "status")
+ attempts := doConfig.HistogramVec("attempts", []float64{0, 1, 2, 3, 4, 5, 7, 10})
+ latency := doConfig.TimerVec("latency")
+ t.OnDo = func(
+ info trace.QueryDoStartInfo,
+ ) func(
+ trace.QueryDoDoneInfo,
+ ) {
+ start := time.Now()
+
+ return func(info trace.QueryDoDoneInfo) {
+ if doConfig.Details()&trace.QueryEvents != 0 {
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ attempts.With(nil).Record(float64(info.Attempts))
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ }
+ {
+ doTxConfig := doConfig.WithSystem("tx")
+ errs := doTxConfig.CounterVec("errs", "status")
+ attempts := doTxConfig.HistogramVec("attempts", []float64{0, 1, 2, 3, 4, 5, 7, 10})
+ latency := doTxConfig.TimerVec("latency")
+ t.OnDoTx = func(
+ info trace.QueryDoTxStartInfo,
+ ) func(
+ trace.QueryDoTxDoneInfo,
+ ) {
+ start := time.Now()
+
+ return func(info trace.QueryDoTxDoneInfo) {
+ if doTxConfig.Details()&trace.QueryEvents != 0 {
+ attempts.With(nil).Record(float64(info.Attempts))
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ }
+ }
+ {
+ sessionConfig := queryConfig.WithSystem("session")
+ count := sessionConfig.GaugeVec("count")
+ {
+ createConfig := sessionConfig.WithSystem("create")
+ errs := createConfig.CounterVec("errs", "status")
+ latency := createConfig.TimerVec("latency")
+ t.OnSessionCreate = func(
+ info trace.QuerySessionCreateStartInfo,
+ ) func(
+ info trace.QuerySessionCreateDoneInfo,
+ ) {
+ start := time.Now()
+
+ return func(info trace.QuerySessionCreateDoneInfo) {
+ if createConfig.Details()&trace.QuerySessionEvents != 0 {
+ if info.Error == nil {
+ count.With(nil).Add(1)
+ }
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ }
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ {
+ deleteConfig := sessionConfig.WithSystem("delete")
+ errs := deleteConfig.CounterVec("errs", "status")
+ latency := deleteConfig.TimerVec("latency")
+ t.OnSessionDelete = func(info trace.QuerySessionDeleteStartInfo) func(info trace.QuerySessionDeleteDoneInfo) {
+ count.With(nil).Add(-1)
+
+ start := time.Now()
+
+ return func(info trace.QuerySessionDeleteDoneInfo) {
+ if deleteConfig.Details()&trace.QuerySessionEvents != 0 {
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ }
+ {
+ executeConfig := sessionConfig.WithSystem("execute")
+ errs := executeConfig.CounterVec("errs", "status")
+ latency := executeConfig.TimerVec("latency")
+ t.OnSessionExecute = func(info trace.QuerySessionExecuteStartInfo) func(info trace.QuerySessionExecuteDoneInfo) {
+ start := time.Now()
+
+ return func(info trace.QuerySessionExecuteDoneInfo) {
+ if executeConfig.Details()&trace.QuerySessionEvents != 0 {
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ }
+ {
+ beginConfig := sessionConfig.WithSystem("begin")
+ errs := beginConfig.CounterVec("errs", "status")
+ latency := beginConfig.TimerVec("latency")
+ t.OnSessionBegin = func(info trace.QuerySessionBeginStartInfo) func(info trace.QuerySessionBeginDoneInfo) {
+ start := time.Now()
+
+ return func(info trace.QuerySessionBeginDoneInfo) {
+ if beginConfig.Details()&trace.QuerySessionEvents != 0 {
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ }
+ }
+ {
+ txConfig := queryConfig.WithSystem("tx")
+ {
+ executeConfig := txConfig.WithSystem("execute")
+ errs := executeConfig.CounterVec("errs", "status")
+ latency := executeConfig.TimerVec("latency")
+ t.OnTxExecute = func(info trace.QueryTxExecuteStartInfo) func(info trace.QueryTxExecuteDoneInfo) {
+ start := time.Now()
+
+ return func(info trace.QueryTxExecuteDoneInfo) {
+ if executeConfig.Details()&trace.QuerySessionEvents != 0 {
+ errs.With(map[string]string{
+ "status": errorBrief(info.Error),
+ }).Inc()
+ latency.With(nil).Record(time.Since(start))
+ }
+ }
+ }
+ }
+ }
+
+ return t
+}
diff --git a/metrics/retry.go b/metrics/retry.go
index 0670a5d6e..994fd493e 100644
--- a/metrics/retry.go
+++ b/metrics/retry.go
@@ -11,36 +11,29 @@ func retry(config Config) (t trace.Retry) {
errs := config.CounterVec("errors", "status", "retry_label", "final")
attempts := config.HistogramVec("attempts", []float64{0, 1, 2, 3, 4, 5, 7, 10}, "retry_label")
latency := config.TimerVec("latency", "retry_label")
- t.OnRetry = func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ t.OnRetry = func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
label := info.Label
if label == "" {
return nil
}
start := time.Now()
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- if info.Error != nil && config.Details()&trace.RetryEvents != 0 {
+
+ return func(info trace.RetryLoopDoneInfo) {
+ if config.Details()&trace.RetryEvents != 0 {
+ attempts.With(map[string]string{
+ "retry_label": label,
+ }).Record(float64(info.Attempts))
errs.With(map[string]string{
"status": errorBrief(info.Error),
"retry_label": label,
- "final": "false",
+ "final": "true",
}).Inc()
- }
- return func(info trace.RetryLoopDoneInfo) {
- if config.Details()&trace.RetryEvents != 0 {
- attempts.With(map[string]string{
- "retry_label": label,
- }).Record(float64(info.Attempts))
- errs.With(map[string]string{
- "status": errorBrief(info.Error),
- "retry_label": label,
- "final": "true",
- }).Inc()
- latency.With(map[string]string{
- "retry_label": label,
- }).Record(time.Since(start))
- }
+ latency.With(map[string]string{
+ "retry_label": label,
+ }).Record(time.Since(start))
}
}
}
+
return t
}
diff --git a/metrics/sql.go b/metrics/sql.go
index a0ff32c69..66b1303a2 100644
--- a/metrics/sql.go
+++ b/metrics/sql.go
@@ -37,6 +37,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
}
}
}
+
return nil
}
t.OnConnClose = func(info trace.DatabaseSQLConnCloseStartInfo) func(trace.DatabaseSQLConnCloseDoneInfo) {
@@ -45,6 +46,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
conns.With(nil).Add(-1)
}
}
+
return nil
}
t.OnConnBegin = func(info trace.DatabaseSQLConnBeginStartInfo) func(trace.DatabaseSQLConnBeginDoneInfo) {
@@ -57,10 +59,12 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
txBeginLatency.With(nil).Record(time.Since(start))
}
}
+
return nil
}
t.OnTxCommit = func(info trace.DatabaseSQLTxCommitStartInfo) func(trace.DatabaseSQLTxCommitDoneInfo) {
start := time.Now()
+
return func(info trace.DatabaseSQLTxCommitDoneInfo) {
if config.Details()&trace.DatabaseSQLTxEvents != 0 {
txCommit.With(map[string]string{
@@ -72,6 +76,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
}
t.OnTxExec = func(info trace.DatabaseSQLTxExecStartInfo) func(trace.DatabaseSQLTxExecDoneInfo) {
start := time.Now()
+
return func(info trace.DatabaseSQLTxExecDoneInfo) {
if config.Details()&trace.DatabaseSQLTxEvents != 0 {
status := errorBrief(info.Error)
@@ -84,6 +89,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
}
t.OnTxQuery = func(info trace.DatabaseSQLTxQueryStartInfo) func(trace.DatabaseSQLTxQueryDoneInfo) {
start := time.Now()
+
return func(info trace.DatabaseSQLTxQueryDoneInfo) {
if config.Details()&trace.DatabaseSQLTxEvents != 0 {
status := errorBrief(info.Error)
@@ -96,6 +102,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
}
t.OnTxRollback = func(info trace.DatabaseSQLTxRollbackStartInfo) func(trace.DatabaseSQLTxRollbackDoneInfo) {
start := time.Now()
+
return func(info trace.DatabaseSQLTxRollbackDoneInfo) {
if config.Details()&trace.DatabaseSQLTxEvents != 0 {
txRollback.With(map[string]string{
@@ -113,6 +120,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
mode = info.Mode
start = time.Now()
)
+
return func(info trace.DatabaseSQLConnExecDoneInfo) {
if config.Details()&trace.DatabaseSQLEvents != 0 {
inflight.With(nil).Add(-1)
@@ -137,6 +145,7 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
mode = info.Mode
start = time.Now()
)
+
return func(info trace.DatabaseSQLConnQueryDoneInfo) {
if config.Details()&trace.DatabaseSQLEvents != 0 {
inflight.With(nil).Add(-1)
@@ -153,5 +162,6 @@ func databaseSQL(config Config) (t trace.DatabaseSQL) {
}
}
}
+
return t
}
diff --git a/metrics/table.go b/metrics/table.go
index 1b04bcc53..80dda3cec 100644
--- a/metrics/table.go
+++ b/metrics/table.go
@@ -38,6 +38,7 @@ func table(config Config) (t trace.Table) {
"node_id": idToString(info.Session.NodeID()),
}).Add(-1)
}
+
return nil
}
t.OnPoolSessionAdd = func(info trace.TablePoolSessionAddInfo) {
@@ -54,6 +55,7 @@ func table(config Config) (t trace.Table) {
t.OnPoolGet = func(info trace.TablePoolGetStartInfo) func(trace.TablePoolGetDoneInfo) {
wait.With(nil).Add(1)
start := time.Now()
+
return func(info trace.TablePoolGetDoneInfo) {
wait.With(nil).Add(-1)
if info.Error == nil && config.Details()&trace.TablePoolEvents != 0 {
@@ -72,7 +74,9 @@ func table(config Config) (t trace.Table) {
}
inflightLatency.With(nil).Record(time.Since(start.(time.Time)))
}
+
return nil
}
+
return t
}
diff --git a/metrics/traces.go b/metrics/traces.go
index 5fc978606..7744ebbcb 100644
--- a/metrics/traces.go
+++ b/metrics/traces.go
@@ -9,9 +9,11 @@ func WithTraces(config Config) ydb.Option {
return nil
}
config = config.WithSystem("ydb")
+
return ydb.MergeOptions(
ydb.WithTraceDriver(driver(config)),
ydb.WithTraceTable(table(config)),
+ ydb.WithTraceQuery(query(config)),
ydb.WithTraceScripting(scripting(config)),
ydb.WithTraceScheme(scheme(config)),
ydb.WithTraceCoordination(coordination(config)),
diff --git a/options.go b/options.go
index a61ba7178..9734b9b75 100644
--- a/options.go
+++ b/options.go
@@ -17,6 +17,7 @@ import (
coordinationConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/coordination/config"
discoveryConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/discovery/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/dsn"
+ queryConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
ratelimiterConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/ratelimiter/config"
schemeConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/scheme/config"
scriptingConfig "github.com/ydb-platform/ydb-go-sdk/v3/internal/scripting/config"
@@ -53,10 +54,21 @@ func WithAccessTokenCredentials(accessToken string) Option {
)
}
+// WithApplicationName add provided application name to all api requests
+func WithApplicationName(applicationName string) Option {
+ return func(ctx context.Context, c *Driver) error {
+ c.options = append(c.options, config.WithApplicationName(applicationName))
+
+ return nil
+ }
+}
+
// WithUserAgent add provided user agent value to all api requests
+//
+// Deprecated: use WithApplicationName instead
func WithUserAgent(userAgent string) Option {
return func(ctx context.Context, c *Driver) error {
- c.options = append(c.options, config.WithUserAgent(userAgent))
+ c.options = append(c.options, config.WithApplicationName(userAgent))
return nil
}
@@ -246,9 +258,9 @@ func With(options ...config.Option) Option {
// MergeOptions concatentaes provided options to one cumulative value.
func MergeOptions(opts ...Option) Option {
return func(ctx context.Context, c *Driver) error {
- for _, o := range opts {
- if o != nil {
- if err := o(ctx, c); err != nil {
+ for _, opt := range opts {
+ if opt != nil {
+ if err := opt(ctx, c); err != nil {
return xerrors.WithStackTrace(err)
}
}
@@ -367,22 +379,26 @@ func WithTableConfigOption(option tableConfig.Option) Option {
}
}
+// WithQueryConfigOption collects additional configuration options for query.Client.
+// This option does not replace collected option, instead it will appen provided options.
+func WithQueryConfigOption(option queryConfig.Option) Option {
+ return func(ctx context.Context, c *Driver) error {
+ c.queryOptions = append(c.queryOptions, option)
+
+ return nil
+ }
+}
+
// WithSessionPoolSizeLimit set max size of internal sessions pool in table.Client
func WithSessionPoolSizeLimit(sizeLimit int) Option {
return func(ctx context.Context, c *Driver) error {
c.tableOptions = append(c.tableOptions, tableConfig.WithSizeLimit(sizeLimit))
+ c.queryOptions = append(c.queryOptions, queryConfig.WithPoolLimit(sizeLimit))
return nil
}
}
-// WithSessionPoolKeepAliveMinSize set minimum sessions should be keeped alive in table.Client
-//
-// Deprecated: table client do not supports background session keep-aliving now
-func WithSessionPoolKeepAliveMinSize(keepAliveMinSize int) Option {
- return func(ctx context.Context, c *Driver) error { return nil }
-}
-
// WithSessionPoolIdleThreshold defines interval for idle sessions
func WithSessionPoolIdleThreshold(idleThreshold time.Duration) Option {
return func(ctx context.Context, c *Driver) error {
@@ -396,15 +412,11 @@ func WithSessionPoolIdleThreshold(idleThreshold time.Duration) Option {
}
}
-// WithSessionPoolKeepAliveTimeout set timeout of keep alive requests for session in table.Client
-func WithSessionPoolKeepAliveTimeout(keepAliveTimeout time.Duration) Option {
- return func(ctx context.Context, c *Driver) error { return nil }
-}
-
// WithSessionPoolCreateSessionTimeout set timeout for new session creation process in table.Client
func WithSessionPoolCreateSessionTimeout(createSessionTimeout time.Duration) Option {
return func(ctx context.Context, c *Driver) error {
c.tableOptions = append(c.tableOptions, tableConfig.WithCreateSessionTimeout(createSessionTimeout))
+ c.queryOptions = append(c.queryOptions, queryConfig.WithSessionCreateTimeout(createSessionTimeout))
return nil
}
@@ -414,6 +426,7 @@ func WithSessionPoolCreateSessionTimeout(createSessionTimeout time.Duration) Opt
func WithSessionPoolDeleteTimeout(deleteTimeout time.Duration) Option {
return func(ctx context.Context, c *Driver) error {
c.tableOptions = append(c.tableOptions, tableConfig.WithDeleteTimeout(deleteTimeout))
+ c.queryOptions = append(c.queryOptions, queryConfig.WithSessionDeleteTimeout(deleteTimeout))
return nil
}
@@ -461,6 +474,25 @@ func WithTraceTable(t trace.Table, opts ...trace.TableComposeOption) Option { //
}
}
+// WithTraceQuery appends trace.Query into query traces
+func WithTraceQuery(t trace.Query, opts ...trace.QueryComposeOption) Option { //nolint:gocritic
+ return func(ctx context.Context, c *Driver) error {
+ c.queryOptions = append(
+ c.queryOptions,
+ queryConfig.WithTrace(&t,
+ append(
+ []trace.QueryComposeOption{
+ trace.WithQueryPanicCallback(c.panicCallback),
+ },
+ opts...,
+ )...,
+ ),
+ )
+
+ return nil
+ }
+}
+
// WithTraceScripting scripting trace option
func WithTraceScripting(t trace.Scripting, opts ...trace.ScriptingComposeOption) Option {
return func(ctx context.Context, c *Driver) error {
diff --git a/params_builder.go b/params_builder.go
new file mode 100644
index 000000000..e9e3f5dfb
--- /dev/null
+++ b/params_builder.go
@@ -0,0 +1,12 @@
+package ydb
+
+import "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+
+// ParamsBuilder used for create query arguments instead of tons options.
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+func ParamsBuilder() params.Builder {
+ return params.Builder{}
+}
diff --git a/query/client.go b/query/client.go
new file mode 100644
index 000000000..87fedc52b
--- /dev/null
+++ b/query/client.go
@@ -0,0 +1,68 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+type Client interface {
+ // Do provide the best effort for execute operation.
+ //
+ // Do implements internal busy loop until one of the following conditions is met:
+ // - deadline was canceled or deadlined
+ // - retry operation returned nil as error
+ //
+ // Warning: if context without deadline or cancellation func than Do can run indefinitely.
+ Do(ctx context.Context, op Operation, opts ...options.DoOption) error
+
+ // DoTx provide the best effort for execute transaction.
+ //
+ // DoTx implements internal busy loop until one of the following conditions is met:
+ // - deadline was canceled or deadlined
+ // - retry operation returned nil as error
+ //
+ // DoTx makes auto selector (with TransactionSettings, by default - SerializableReadWrite), commit and
+ // rollback (on error) of transaction.
+ //
+ // If op TxOperation returns nil - transaction will be committed
+ // If op TxOperation return non nil - transaction will be rollback
+ // Warning: if context without deadline or cancellation func than DoTx can run indefinitely
+ DoTx(ctx context.Context, op TxOperation, opts ...options.DoTxOption) error
+}
+
+type (
+ // Operation is the interface that holds an operation for retry.
+ // if Operation returns not nil - operation will retry
+ // if Operation returns nil - retry loop will break
+ Operation func(ctx context.Context, s Session) error
+
+ // TxOperation is the interface that holds an operation for retry.
+ // if TxOperation returns not nil - operation will retry
+ // if TxOperation returns nil - retry loop will break
+ TxOperation func(ctx context.Context, tx TxActor) error
+
+ ClosableSession interface {
+ closer.Closer
+
+ Session
+ }
+ bothDoAndDoTxOption interface {
+ options.DoOption
+ options.DoTxOption
+ }
+)
+
+func WithIdempotent() bothDoAndDoTxOption {
+ return options.WithIdempotent()
+}
+
+func WithTrace(t *trace.Query) bothDoAndDoTxOption {
+ return options.WithTrace(t)
+}
+
+func WithLabel(lbl string) bothDoAndDoTxOption {
+ return options.WithLabel(lbl)
+}
diff --git a/query/example_test.go b/query/example_test.go
new file mode 100644
index 000000000..c0dec4c30
--- /dev/null
+++ b/query/example_test.go
@@ -0,0 +1,198 @@
+package query_test
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+)
+
+func Example_selectWithoutParameters() {
+ ctx := context.TODO()
+ db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
+ if err != nil {
+ fmt.Printf("failed connect: %v", err)
+
+ return
+ }
+ defer db.Close(ctx) // cleanup resources
+ var (
+ id int32 // required value
+ myStr string // optional value
+ )
+ // Do retry operation on errors with best effort
+ err = db.Query().Do(ctx, // context manage exiting from Do
+ func(ctx context.Context, s query.Session) (err error) { // retry operation
+ _, res, err := s.Execute(ctx,
+ `SELECT 42 as id, "my string" as myStr`,
+ )
+ if err != nil {
+ return err // for auto-retry with driver
+ }
+ defer func() { _ = res.Close(ctx) }() // cleanup resources
+ for { // iterate over result sets
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ for { // iterate over rows
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ if err = row.Scan(&id, &myStr); err != nil {
+ return err // generally scan error not retryable, return it for driver check error
+ }
+ }
+ }
+
+ return res.Err() // return finally result error for auto-retry with driver
+ },
+ query.WithIdempotent(),
+ )
+ if err != nil {
+ fmt.Printf("unexpected error: %v", err)
+ }
+ fmt.Printf("id=%v, myStr='%s'\n", id, myStr)
+}
+
+func Example_selectWithParameters() {
+ ctx := context.TODO()
+ db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
+ if err != nil {
+ fmt.Printf("failed connect: %v", err)
+
+ return
+ }
+ defer db.Close(ctx) // cleanup resources
+ var (
+ id int32 // required value
+ myStr string // optional value
+ )
+ // Do retry operation on errors with best effort
+ err = db.Query().Do(ctx, // context manage exiting from Do
+ func(ctx context.Context, s query.Session) (err error) { // retry operation
+ _, res, err := s.Execute(ctx,
+ `SELECT CAST($id AS Uint64) AS id, CAST($myStr AS Text) AS myStr`,
+ options.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$id").Uint64(123).
+ Param("$myStr").Text("123").
+ Build(),
+ ),
+ )
+ if err != nil {
+ return err // for auto-retry with driver
+ }
+ defer func() { _ = res.Close(ctx) }() // cleanup resources
+ for { // iterate over result sets
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ for { // iterate over rows
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ if err = row.ScanNamed(
+ query.Named("id", &id),
+ query.Named("myStr", &myStr),
+ ); err != nil {
+ return err // generally scan error not retryable, return it for driver check error
+ }
+ }
+ }
+
+ return res.Err() // return finally result error for auto-retry with driver
+ },
+ options.WithIdempotent(),
+ )
+ if err != nil {
+ fmt.Printf("unexpected error: %v", err)
+ }
+ fmt.Printf("id=%v, myStr='%s'\n", id, myStr)
+}
+
+func Example_txSelect() {
+ ctx := context.TODO()
+ db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
+ if err != nil {
+ fmt.Printf("failed connect: %v", err)
+
+ return
+ }
+ defer db.Close(ctx) // cleanup resources
+ var (
+ id int32 // required value
+ myStr string // optional value
+ )
+ // Do retry operation on errors with best effort
+ err = db.Query().DoTx(ctx, // context manage exiting from Do
+ func(ctx context.Context, tx query.TxActor) (err error) { // retry operation
+ res, err := tx.Execute(ctx,
+ `SELECT 42 as id, "my string" as myStr`,
+ )
+ if err != nil {
+ return err // for auto-retry with driver
+ }
+ defer func() { _ = res.Close(ctx) }() // cleanup resources
+ for { // iterate over result sets
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ for { // iterate over rows
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ if err = row.ScanNamed(
+ query.Named("id", &id),
+ query.Named("myStr", &myStr),
+ ); err != nil {
+ return err // generally scan error not retryable, return it for driver check error
+ }
+ }
+ }
+
+ return res.Err() // return finally result error for auto-retry with driver
+ },
+ options.WithIdempotent(),
+ options.WithTxSettings(query.TxSettings(
+ query.WithSnapshotReadOnly(),
+ )),
+ )
+ if err != nil {
+ fmt.Printf("unexpected error: %v", err)
+ }
+ fmt.Printf("id=%v, myStr='%s'\n", id, myStr)
+}
diff --git a/query/result.go b/query/result.go
new file mode 100644
index 000000000..3cef8e9ee
--- /dev/null
+++ b/query/result.go
@@ -0,0 +1,41 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/scanner"
+)
+
+type (
+ Result interface {
+ closer.Closer
+
+ NextResultSet(ctx context.Context) (ResultSet, error)
+ Err() error
+ }
+ ResultSet interface {
+ NextRow(ctx context.Context) (Row, error)
+ }
+ Row interface {
+ Scan(dst ...interface{}) error
+ ScanNamed(dst ...scanner.NamedDestination) error
+ ScanStruct(dst interface{}, opts ...scanner.ScanStructOption) error
+ }
+)
+
+func Named(columnName string, destinationValueReference interface{}) (dst scanner.NamedDestination) {
+ return scanner.NamedRef(columnName, destinationValueReference)
+}
+
+func WithScanStructTagName(name string) scanner.ScanStructOption {
+ return scanner.WithTagName(name)
+}
+
+func WithScanStructAllowMissingColumnsFromSelect() scanner.ScanStructOption {
+ return scanner.WithAllowMissingColumnsFromSelect()
+}
+
+func WithScanStructAllowMissingFieldsInStruct() scanner.ScanStructOption {
+ return scanner.WithAllowMissingFieldsInStruct()
+}
diff --git a/query/session.go b/query/session.go
new file mode 100644
index 000000000..9a92449eb
--- /dev/null
+++ b/query/session.go
@@ -0,0 +1,83 @@
+package query
+
+import (
+ "context"
+
+ "google.golang.org/grpc"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/tx"
+)
+
+type (
+ SessionInfo interface {
+ ID() string
+ NodeID() int64
+ Status() string
+ }
+
+ Session interface {
+ SessionInfo
+
+ // Execute executes query.
+ //
+ // Execute used by default:
+ // - DefaultTxControl
+ // - flag WithKeepInCache(true) if params is not empty.
+ Execute(ctx context.Context, query string, opts ...options.ExecuteOption) (tx Transaction, r Result, err error)
+
+ Begin(ctx context.Context, txSettings TransactionSettings) (Transaction, error)
+ }
+)
+
+const (
+ SyntaxYQL = options.SyntaxYQL
+ SyntaxPostgreSQL = options.SyntaxPostgreSQL
+)
+
+const (
+ ExecModeParse = options.ExecModeParse
+ ExecModeValidate = options.ExecModeValidate
+ ExecModeExplain = options.ExecModeExplain
+ ExecModeExecute = options.ExecModeExecute
+)
+
+const (
+ StatsModeBasic = options.StatsModeBasic
+ StatsModeNone = options.StatsModeNone
+ StatsModeFull = options.StatsModeFull
+ StatsModeProfile = options.StatsModeProfile
+)
+
+func WithParameters(parameters *params.Parameters) options.ParametersOption {
+ return options.WithParameters(parameters)
+}
+
+func WithTxControl(txControl *tx.Control) options.TxControlOption {
+ return options.WithTxControl(txControl)
+}
+
+func WithTxSettings(txSettings tx.Settings) options.DoTxOption {
+ return options.WithTxSettings(txSettings)
+}
+
+func WithCommit() options.TxExecuteOption {
+ return options.WithCommit()
+}
+
+func WithExecMode(mode options.ExecMode) options.ExecModeOption {
+ return options.WithExecMode(mode)
+}
+
+func WithSyntax(syntax options.Syntax) options.SyntaxOption {
+ return options.WithSyntax(syntax)
+}
+
+func WithStatsMode(mode options.StatsMode) options.StatsModeOption {
+ return options.WithStatsMode(mode)
+}
+
+func WithCallOptions(opts ...grpc.CallOption) options.CallOptions {
+ return options.WithCallOptions(opts...)
+}
diff --git a/query/stats.go b/query/stats.go
new file mode 100644
index 000000000..f93b8867c
--- /dev/null
+++ b/query/stats.go
@@ -0,0 +1,18 @@
+package query
+
+import (
+ "fmt"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/pool/stats"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+)
+
+func Stats(client Client) (*stats.Stats, error) {
+ if c, has := client.(interface {
+ Stats() *stats.Stats
+ }); has {
+ return c.Stats(), nil
+ }
+
+ return nil, xerrors.WithStackTrace(fmt.Errorf("client %T not supported stats", client))
+}
diff --git a/query/transaction.go b/query/transaction.go
new file mode 100644
index 000000000..877c93296
--- /dev/null
+++ b/query/transaction.go
@@ -0,0 +1,125 @@
+package query
+
+import (
+ "context"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/tx"
+)
+
+type (
+ TxIdentifier interface {
+ ID() string
+ }
+ TxActor interface {
+ TxIdentifier
+
+ // Execute executes query.
+ //
+ // Execute used by default:
+ // - DefaultTxControl
+ // - flag WithKeepInCache(true) if params is not empty.
+ Execute(ctx context.Context, query string, opts ...options.TxExecuteOption) (r Result, err error)
+ }
+ Transaction interface {
+ TxActor
+
+ CommitTx(ctx context.Context) (err error)
+ Rollback(ctx context.Context) (err error)
+ }
+ TransactionControl = tx.Control
+ TransactionSettings = tx.Settings
+)
+
+// BeginTx returns selector transaction control option
+func BeginTx(opts ...tx.Option) tx.ControlOption {
+ return tx.BeginTx(opts...)
+}
+
+func WithTx(t tx.Identifier) tx.ControlOption {
+ return tx.WithTx(t)
+}
+
+func WithTxID(txID string) tx.ControlOption {
+ return tx.WithTxID(txID)
+}
+
+// CommitTx returns commit transaction control option
+func CommitTx() tx.ControlOption {
+ return tx.CommitTx()
+}
+
+// TxControl makes transaction control from given options
+func TxControl(opts ...tx.ControlOption) *TransactionControl {
+ return tx.NewControl(opts...)
+}
+
+func NoTx() *TransactionControl {
+ return nil
+}
+
+// DefaultTxControl returns default transaction control with serializable read-write isolation mode and auto-commit
+func DefaultTxControl() *TransactionControl {
+ return TxControl(
+ BeginTx(WithSerializableReadWrite()),
+ CommitTx(),
+ )
+}
+
+// SerializableReadWriteTxControl returns transaction control with serializable read-write isolation mode
+func SerializableReadWriteTxControl(opts ...tx.ControlOption) *TransactionControl {
+ return tx.SerializableReadWriteTxControl(opts...)
+}
+
+// OnlineReadOnlyTxControl returns online read-only transaction control
+func OnlineReadOnlyTxControl(opts ...tx.OnlineReadOnlyOption) *TransactionControl {
+ return TxControl(
+ BeginTx(WithOnlineReadOnly(opts...)),
+ CommitTx(), // open transactions not supported for OnlineReadOnly
+ )
+}
+
+// StaleReadOnlyTxControl returns stale read-only transaction control
+func StaleReadOnlyTxControl() *TransactionControl {
+ return TxControl(
+ BeginTx(WithStaleReadOnly()),
+ CommitTx(), // open transactions not supported for StaleReadOnly
+ )
+}
+
+// SnapshotReadOnlyTxControl returns snapshot read-only transaction control
+func SnapshotReadOnlyTxControl() *TransactionControl {
+ return TxControl(
+ BeginTx(WithSnapshotReadOnly()),
+ CommitTx(), // open transactions not supported for StaleReadOnly
+ )
+}
+
+// TxSettings returns transaction settings
+func TxSettings(opts ...tx.Option) TransactionSettings {
+ return opts
+}
+
+func WithDefaultTxMode() tx.Option {
+ return tx.WithDefaultTxMode()
+}
+
+func WithSerializableReadWrite() tx.Option {
+ return tx.WithSerializableReadWrite()
+}
+
+func WithSnapshotReadOnly() tx.Option {
+ return tx.WithSnapshotReadOnly()
+}
+
+func WithStaleReadOnly() tx.Option {
+ return tx.WithStaleReadOnly()
+}
+
+func WithInconsistentReads() tx.OnlineReadOnlyOption {
+ return tx.WithInconsistentReads()
+}
+
+func WithOnlineReadOnly(opts ...tx.OnlineReadOnlyOption) tx.Option {
+ return tx.WithOnlineReadOnly(opts...)
+}
diff --git a/query_bind_test.go b/query_bind_test.go
index 24870c0c9..3ffa07c80 100644
--- a/query_bind_test.go
+++ b/query_bind_test.go
@@ -9,6 +9,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/bind"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
"github.com/ydb-platform/ydb-go-sdk/v3/testutil"
@@ -567,14 +568,14 @@ SELECT $param1, $param2`,
},
} {
t.Run("", func(t *testing.T) {
- yql, params, err := tt.b.RewriteQuery(tt.sql, tt.args...)
+ yql, parameters, err := tt.b.RewriteQuery(tt.sql, tt.args...)
if tt.err != nil {
require.Error(t, err)
require.ErrorIs(t, err, tt.err)
} else {
require.NoError(t, err)
require.Equal(t, tt.yql, yql)
- require.Equal(t, tt.params, params)
+ require.Equal(t, []*params.Parameter(*tt.params), parameters)
}
})
}
diff --git a/ratelimiter/example_test.go b/ratelimiter/example_test.go
index b64afde4f..12f179bba 100644
--- a/ratelimiter/example_test.go
+++ b/ratelimiter/example_test.go
@@ -14,6 +14,7 @@ func Example() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -28,6 +29,7 @@ func Example() {
})
if err != nil {
fmt.Printf("failed to create node: %v", err)
+
return
}
defer func() {
diff --git a/retry/context.go b/retry/context.go
index ed2063070..a3898fc0b 100644
--- a/retry/context.go
+++ b/retry/context.go
@@ -22,5 +22,6 @@ func WithNonIdempotentOperation(ctx context.Context) context.Context {
// Deprecated: context cannot store idempotent value now
func IsOperationIdempotent(ctx context.Context) bool {
v, ok := ctx.Value(ctxIsOperationIdempotentKey{}).(bool)
+
return ok && v
}
diff --git a/retry/errors.go b/retry/errors.go
index ed540018f..4c091a720 100644
--- a/retry/errors.go
+++ b/retry/errors.go
@@ -10,5 +10,6 @@ func unwrapErrBadConn(err error) error {
if xerrors.As(err, &e) {
return e.Origin()
}
+
return err
}
diff --git a/retry/errors_data_test.go b/retry/errors_data_test.go
index b8dcddcd8..5253b505f 100644
--- a/retry/errors_data_test.go
+++ b/retry/errors_data_test.go
@@ -19,6 +19,7 @@ func (t idempotency) String() string {
if t {
return "idempotent"
}
+
return "non-idempotent"
}
@@ -207,7 +208,7 @@ var errsToCheck = []struct {
err: xerrors.Retryable(
xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, "")),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
backoff: backoff.TypeFast,
deleteSession: true,
@@ -220,7 +221,7 @@ var errsToCheck = []struct {
err: xerrors.Retryable(
grpcStatus.Error(grpcCodes.Unavailable, ""),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
backoff: backoff.TypeFast,
deleteSession: true,
@@ -408,7 +409,7 @@ var errsToCheck = []struct {
backoff: backoff.TypeNoBackoff,
deleteSession: true,
canRetry: map[idempotency]bool{
- idempotent: false,
+ idempotent: true,
nonIdempotent: false,
},
},
diff --git a/retry/mode.go b/retry/mode.go
index 385cf170b..32736e9c3 100644
--- a/retry/mode.go
+++ b/retry/mode.go
@@ -7,10 +7,10 @@ import (
// retryMode reports whether operation is able retried and with which properties.
type retryMode struct {
- code int64
- errType xerrors.Type
- backoff backoff.Type
- deleteSession bool
+ code int64
+ errType xerrors.Type
+ backoff backoff.Type
+ isRetryObjectValid bool
}
func (m retryMode) MustRetry(isOperationIdempotent bool) bool {
@@ -33,4 +33,6 @@ func (m retryMode) MustBackoff() bool { return m.backoff&backoff.TypeAny != 0 }
func (m retryMode) BackoffType() backoff.Type { return m.backoff }
-func (m retryMode) MustDeleteSession() bool { return m.deleteSession }
+func (m retryMode) MustDeleteSession() bool { return !m.isRetryObjectValid }
+
+func (m retryMode) IsRetryObjectValid() bool { return m.isRetryObjectValid }
diff --git a/retry/retry.go b/retry/retry.go
index 50f9c0b99..16b1050bf 100644
--- a/retry/retry.go
+++ b/retry/retry.go
@@ -232,7 +232,7 @@ func WithPanicCallback(panicCallback func(e interface{})) panicCallbackOption {
// If you need to retry your op func on some logic errors - you must return RetryableError() from retryOperation
func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr error) {
options := &retryOptions{
- call: stack.FunctionID(""),
+ call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.Retry"),
trace: &trace.Retry{},
fastBackoff: backoff.Fast,
slowBackoff: backoff.Slow,
@@ -256,13 +256,13 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
i int
attempts int
- code = int64(0)
- onIntermediate = trace.RetryOnRetry(options.trace, &ctx,
- options.label, options.call, options.label, options.idempotent, xcontext.IsNestedCall(ctx),
+ code = int64(0)
+ onDone = trace.RetryOnRetry(options.trace, &ctx,
+ options.call, options.label, options.idempotent, xcontext.IsNestedCall(ctx),
)
)
defer func() {
- onIntermediate(finalErr)(attempts, finalErr)
+ onDone(attempts, finalErr)
}()
for {
i++
@@ -287,6 +287,7 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
}
}()
}
+
return op(ctx)
}()
@@ -328,8 +329,6 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
}
code = m.StatusCode()
-
- onIntermediate(err)
}
}
}
@@ -337,10 +336,11 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
// Check returns retry mode for queryErr.
func Check(err error) (m retryMode) {
code, errType, backoffType, deleteSession := xerrors.Check(err)
+
return retryMode{
- code: code,
- errType: errType,
- backoff: backoffType,
- deleteSession: deleteSession,
+ code: code,
+ errType: errType,
+ backoff: backoffType,
+ isRetryObjectValid: deleteSession,
}
}
diff --git a/retry/retry_test.go b/retry/retry_test.go
index bb9818775..770f2ea65 100644
--- a/retry/retry_test.go
+++ b/retry/retry_test.go
@@ -45,10 +45,10 @@ func TestRetryModes(t *testing.T) {
tt.backoff,
)
}
- if m.MustDeleteSession() != tt.deleteSession {
+ if m.IsRetryObjectValid() != tt.deleteSession {
t.Errorf(
"unexpected delete session status: %v, want: %v",
- m.MustDeleteSession(),
+ m.IsRetryObjectValid(),
tt.deleteSession,
)
}
@@ -126,6 +126,7 @@ func TestRetryWithCustomErrors(t *testing.T) {
if i < limit {
return tt.error
}
+
return nil
})
if tt.retriable {
@@ -147,17 +148,20 @@ func TestRetryTransportDeadlineExceeded(t *testing.T) {
grpcCodes.DeadlineExceeded,
grpcCodes.Canceled,
} {
- counter := 0
- ctx, cancel := xcontext.WithTimeout(context.Background(), time.Hour)
- err := Retry(ctx, func(ctx context.Context) error {
- counter++
- if !(counter < cancelCounterValue) {
- cancel()
- }
- return xerrors.Transport(grpcStatus.Error(code, ""))
- }, WithIdempotent(true))
- require.ErrorIs(t, err, context.Canceled)
- require.Equal(t, cancelCounterValue, counter)
+ t.Run(code.String(), func(t *testing.T) {
+ counter := 0
+ ctx, cancel := xcontext.WithTimeout(context.Background(), time.Hour)
+ err := Retry(ctx, func(ctx context.Context) error {
+ counter++
+ if !(counter < cancelCounterValue) {
+ cancel()
+ }
+
+ return xerrors.Transport(grpcStatus.Error(code, ""))
+ }, WithIdempotent(true))
+ require.ErrorIs(t, err, context.Canceled)
+ require.Equal(t, cancelCounterValue, counter)
+ })
}
}
@@ -167,16 +171,19 @@ func TestRetryTransportCancelled(t *testing.T) {
grpcCodes.DeadlineExceeded,
grpcCodes.Canceled,
} {
- counter := 0
- ctx, cancel := xcontext.WithCancel(context.Background())
- err := Retry(ctx, func(ctx context.Context) error {
- counter++
- if !(counter < cancelCounterValue) {
- cancel()
- }
- return xerrors.Transport(grpcStatus.Error(code, ""))
- }, WithIdempotent(true))
- require.ErrorIs(t, err, context.Canceled)
- require.Equal(t, cancelCounterValue, counter)
+ t.Run(code.String(), func(t *testing.T) {
+ counter := 0
+ ctx, cancel := xcontext.WithCancel(context.Background())
+ err := Retry(ctx, func(ctx context.Context) error {
+ counter++
+ if !(counter < cancelCounterValue) {
+ cancel()
+ }
+
+ return xerrors.Transport(grpcStatus.Error(code, ""))
+ }, WithIdempotent(true))
+ require.ErrorIs(t, err, context.Canceled)
+ require.Equal(t, cancelCounterValue, counter)
+ })
}
}
diff --git a/retry/retryable_error.go b/retry/retryable_error.go
index 441da19ae..ca273aac7 100644
--- a/retry/retryable_error.go
+++ b/retry/retryable_error.go
@@ -20,7 +20,7 @@ func WithBackoff(t backoff.Type) retryableErrorOption {
// WithDeleteSession makes retryable error option with delete session flag
func WithDeleteSession() retryableErrorOption {
- return retryableErrorOption(xerrors.WithDeleteSession())
+ return retryableErrorOption(xerrors.InvalidObject())
}
// RetryableError makes retryable error from options
@@ -29,11 +29,12 @@ func RetryableError(err error, opts ...retryableErrorOption) error {
return xerrors.Retryable(
err,
func() (retryableErrorOptions []xerrors.RetryableErrorOption) {
- for _, o := range opts {
- if o != nil {
- retryableErrorOptions = append(retryableErrorOptions, xerrors.RetryableErrorOption(o))
+ for _, opt := range opts {
+ if opt != nil {
+ retryableErrorOptions = append(retryableErrorOptions, xerrors.RetryableErrorOption(opt))
}
}
+
return retryableErrorOptions
}()...,
)
diff --git a/retry/sql.go b/retry/sql.go
index c0525891c..affde98e2 100644
--- a/retry/sql.go
+++ b/retry/sql.go
@@ -42,7 +42,7 @@ func Do(ctx context.Context, db *sql.DB, op func(ctx context.Context, cc *sql.Co
var (
options = doOptions{
retryOptions: []Option{
- withCaller(stack.FunctionID("")),
+ withCaller(stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.Do")),
},
}
attempts = 0
@@ -71,6 +71,7 @@ func Do(ctx context.Context, db *sql.DB, op func(ctx context.Context, cc *sql.Co
if err = op(xcontext.MarkRetryCall(ctx), cc); err != nil {
return unwrapErrBadConn(xerrors.WithStackTrace(err))
}
+
return nil
}, options.retryOptions...)
if err != nil {
@@ -78,6 +79,7 @@ func Do(ctx context.Context, db *sql.DB, op func(ctx context.Context, cc *sql.Co
fmt.Errorf("operation failed with %d attempts: %w", attempts, err),
)
}
+
return nil
}
@@ -127,7 +129,7 @@ func DoTx(ctx context.Context, db *sql.DB, op func(context.Context, *sql.Tx) err
var (
options = doTxOptions{
retryOptions: []Option{
- withCaller(stack.FunctionID("")),
+ withCaller(stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.DoTx")),
},
txOptions: &sql.TxOptions{
Isolation: sql.LevelDefault,
@@ -173,6 +175,7 @@ func DoTx(ctx context.Context, db *sql.DB, op func(context.Context, *sql.Tx) err
if err = tx.Commit(); err != nil {
return unwrapErrBadConn(xerrors.WithStackTrace(err))
}
+
return nil
}, options.retryOptions...)
if err != nil {
@@ -180,5 +183,6 @@ func DoTx(ctx context.Context, db *sql.DB, op func(context.Context, *sql.Tx) err
fmt.Errorf("tx operation failed with %d attempts: %w", attempts, err),
)
}
+
return nil
}
diff --git a/retry/sql_test.go b/retry/sql_test.go
index d4a6c3d5f..d6552493b 100644
--- a/retry/sql_test.go
+++ b/retry/sql_test.go
@@ -11,7 +11,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn"
- "github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
type mockConnector struct {
@@ -25,12 +24,14 @@ var _ driver.Connector = &mockConnector{}
func (m *mockConnector) Open(name string) (driver.Conn, error) {
m.t.Log(stack.Record(0))
+
return nil, driver.ErrSkip
}
func (m *mockConnector) Connect(ctx context.Context) (driver.Conn, error) {
m.t.Log(stack.Record(0))
m.conns++
+
return &mockConn{
t: m.t,
queryErr: m.queryErr,
@@ -40,6 +41,7 @@ func (m *mockConnector) Connect(ctx context.Context) (driver.Conn, error) {
func (m *mockConnector) Driver() driver.Driver {
m.t.Log(stack.Record(0))
+
return m
}
@@ -60,6 +62,7 @@ var (
func (m *mockConn) Prepare(query string) (driver.Stmt, error) {
m.t.Log(stack.Record(0))
+
return nil, driver.ErrSkip
}
@@ -68,6 +71,7 @@ func (m *mockConn) PrepareContext(ctx context.Context, query string) (driver.Stm
if m.closed {
return nil, driver.ErrBadConn
}
+
return &mockStmt{
t: m.t,
conn: m,
@@ -78,11 +82,13 @@ func (m *mockConn) PrepareContext(ctx context.Context, query string) (driver.Stm
func (m *mockConn) Close() error {
m.t.Log(stack.Record(0))
m.closed = true
+
return nil
}
func (m *mockConn) Begin() (driver.Tx, error) {
m.t.Log(stack.Record(0))
+
return nil, driver.ErrSkip
}
@@ -91,32 +97,37 @@ func (m *mockConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.T
if m.closed {
return nil, driver.ErrBadConn
}
+
return m, nil
}
func (m *mockConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
m.t.Log(stack.Record(0))
- if xerrors.MustDeleteSession(m.execErr) {
+ if !xerrors.IsRetryObjectValid(m.execErr) {
m.closed = true
}
+
return nil, m.queryErr
}
func (m *mockConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
m.t.Log(stack.Record(0))
- if xerrors.MustDeleteSession(m.execErr) {
+ if !xerrors.IsRetryObjectValid(m.execErr) {
m.closed = true
}
+
return nil, m.execErr
}
func (m *mockConn) Commit() error {
m.t.Log(stack.Record(0))
+
return nil
}
func (m *mockConn) Rollback() error {
m.t.Log(stack.Record(0))
+
return nil
}
@@ -134,31 +145,37 @@ var (
func (m *mockStmt) Close() error {
m.t.Log(stack.Record(0))
+
return nil
}
func (m *mockStmt) NumInput() int {
m.t.Log(stack.Record(0))
+
return -1
}
func (m *mockStmt) Exec(args []driver.Value) (driver.Result, error) {
m.t.Log(stack.Record(0))
+
return nil, driver.ErrSkip
}
func (m *mockStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
m.t.Log(stack.Record(0))
+
return m.conn.ExecContext(ctx, m.query, args)
}
func (m *mockStmt) Query(args []driver.Value) (driver.Rows, error) {
m.t.Log(stack.Record(0))
+
return nil, driver.ErrSkip
}
func (m *mockStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
m.t.Log(stack.Record(0))
+
return m.conn.QueryContext(ctx, m.query, args)
}
@@ -191,21 +208,12 @@ func TestDoTx(t *testing.T) {
defer func() {
_ = rows.Close()
}()
+
return rows.Err()
},
WithIdempotent(bool(idempotentType)),
WithFastBackoff(backoff.New(backoff.WithSlotDuration(time.Nanosecond))),
WithSlowBackoff(backoff.New(backoff.WithSlotDuration(time.Nanosecond))),
- WithTrace(&trace.Retry{
- //nolint:lll
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- t.Logf("attempt %d, conn %d, mode: %+v", attempts, m.conns, Check(m.queryErr))
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- t.Logf("attempt %d, conn %d, mode: %+v", attempts, m.conns, Check(m.queryErr))
- return nil
- }
- },
- }),
)
if tt.canRetry[idempotentType] {
if err != nil {
diff --git a/scheme/example_test.go b/scheme/example_test.go
index 8f774fd54..3510d7130 100644
--- a/scheme/example_test.go
+++ b/scheme/example_test.go
@@ -12,6 +12,7 @@ func Example() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
diff --git a/scheme/options.go b/scheme/options.go
index 1313f84ca..c23cdf900 100644
--- a/scheme/options.go
+++ b/scheme/options.go
@@ -7,6 +7,7 @@ import (
func permissions(p Permissions) *Ydb_Scheme.Permissions {
var y Ydb_Scheme.Permissions
p.To(&y)
+
return &y
}
diff --git a/scheme/scheme.go b/scheme/scheme.go
index 9887a044c..1aeac9777 100644
--- a/scheme/scheme.go
+++ b/scheme/scheme.go
@@ -110,11 +110,11 @@ func (e *Entry) IsTopic() bool {
func (e *Entry) From(y *Ydb_Scheme.Entry) {
*e = Entry{
- Name: y.Name,
- Owner: y.Owner,
- Type: entryType(y.Type),
- Permissions: makePermissions(y.Permissions),
- EffectivePermissions: makePermissions(y.EffectivePermissions),
+ Name: y.GetName(),
+ Owner: y.GetOwner(),
+ Type: entryType(y.GetType()),
+ Permissions: makePermissions(y.GetPermissions()),
+ EffectivePermissions: makePermissions(y.GetEffectivePermissions()),
}
}
@@ -149,13 +149,14 @@ func makePermissions(src []*Ydb_Scheme.Permissions) (dst []Permissions) {
for _, p := range src {
dst = append(dst, from(p))
}
+
return dst
}
func from(y *Ydb_Scheme.Permissions) (p Permissions) {
return Permissions{
- Subject: y.Subject,
- PermissionNames: y.PermissionNames,
+ Subject: y.GetSubject(),
+ PermissionNames: y.GetPermissionNames(),
}
}
@@ -172,5 +173,6 @@ func (p Permissions) To(y *Ydb_Scheme.Permissions) {
func InnerConvertEntry(y *Ydb_Scheme.Entry) *Entry {
res := &Entry{}
res.From(y)
+
return res
}
diff --git a/scripting/example_test.go b/scripting/example_test.go
index b1b6c76e4..aa96dd85a 100644
--- a/scripting/example_test.go
+++ b/scripting/example_test.go
@@ -15,6 +15,7 @@ func Example_execute() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -47,6 +48,7 @@ func Example_execute() {
if sum != 2 {
return fmt.Errorf("unexpected sum: %v", sum)
}
+
return res.Err()
}, retry.WithIdempotent(true)); err != nil {
fmt.Printf("Execute failed: %v", err)
@@ -58,6 +60,7 @@ func Example_streamExecute() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -91,6 +94,7 @@ func Example_streamExecute() {
if sum != 2 {
return fmt.Errorf("unexpected sum: %v", sum)
}
+
return res.Err()
}, retry.WithIdempotent(true)); err != nil {
fmt.Printf("StreamExecute failed: %v", err)
@@ -102,6 +106,7 @@ func Example_explainPlan() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -112,10 +117,12 @@ func Example_explainPlan() {
)
if err != nil {
fmt.Printf("Explain failed: %v", err)
+
return
}
if res.Plan == "" {
fmt.Printf("Unexpected empty plan")
+
return
}
fmt.Printf("")
@@ -126,6 +133,7 @@ func Example_explainValidate() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed to connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -141,6 +149,7 @@ func Example_explainValidate() {
if len(res.ParameterTypes) > 0 {
return retry.RetryableError(fmt.Errorf("unexpected parameter types"))
}
+
return nil
}, retry.WithIdempotent(true)); err != nil {
fmt.Printf("Explain failed: %v", err)
diff --git a/scripting/scripting.go b/scripting/scripting.go
index dc31def50..048529fee 100644
--- a/scripting/scripting.go
+++ b/scripting/scripting.go
@@ -3,6 +3,7 @@ package scripting
import (
"context"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
)
@@ -21,7 +22,7 @@ type Client interface {
Execute(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ params *params.Parameters,
) (result.Result, error)
Explain(
ctx context.Context,
@@ -31,6 +32,6 @@ type Client interface {
StreamExecute(
ctx context.Context,
query string,
- params *table.QueryParameters,
+ params *params.Parameters,
) (result.StreamResult, error)
}
diff --git a/sugar/certificates.go b/sugar/certificates.go
index 809a4afd4..5ab386c34 100644
--- a/sugar/certificates.go
+++ b/sugar/certificates.go
@@ -15,6 +15,7 @@ func LoadCertificatesFromFile(caFile string) ([]*x509.Certificate, error) {
if err != nil {
return nil, xerrors.WithStackTrace(err)
}
+
return LoadCertificatesFromPem(bytes), nil
}
@@ -40,5 +41,6 @@ func LoadCertificatesFromPem(bytes []byte) (certs []*x509.Certificate) {
}
certs = append(certs, cert)
}
+
return
}
diff --git a/sugar/check_exists.go b/sugar/check_exists.go
index 8aeed03c9..59d27e56a 100644
--- a/sugar/check_exists.go
+++ b/sugar/check_exists.go
@@ -13,6 +13,7 @@ func IsTableExists(ctx context.Context, c scheme.Client, absTablePath string) (e
if err != nil {
return exists, xerrors.WithStackTrace(err)
}
+
return exists, nil
}
@@ -21,6 +22,7 @@ func IsColumnTableExists(ctx context.Context, c scheme.Client, absTablePath stri
if err != nil {
return exists, xerrors.WithStackTrace(err)
}
+
return exists, nil
}
@@ -31,6 +33,7 @@ func IsEntryExists(ctx context.Context, c scheme.Client, absPath string, entryTy
if err != nil {
return exists, xerrors.WithStackTrace(err)
}
+
return exists, nil
}
@@ -39,5 +42,6 @@ func IsDirectoryExists(ctx context.Context, c scheme.Client, absTablePath string
if err != nil {
return exists, xerrors.WithStackTrace(err)
}
+
return exists, nil
}
diff --git a/sugar/params.go b/sugar/params.go
index e8d6691b1..612268260 100644
--- a/sugar/params.go
+++ b/sugar/params.go
@@ -3,35 +3,32 @@ package sugar
import (
"database/sql"
"fmt"
+ "sort"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/bind"
- internal "github.com/ydb-platform/ydb-go-sdk/v3/internal/table"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
)
+type constraint interface {
+ params.Parameters | []*params.Parameter | *table.QueryParameters | []table.ParameterOption | []sql.NamedArg
+}
+
// GenerateDeclareSection generates DECLARE section text in YQL query by params
//
// Deprecated: use testutil.QueryBind(ydb.WithAutoDeclare()) helper
-func GenerateDeclareSection[T *table.QueryParameters | []table.ParameterOption | []sql.NamedArg](
- params T,
-) (string, error) {
- switch v := any(params).(type) {
- case *table.QueryParameters:
- return internal.GenerateDeclareSection(v)
+func GenerateDeclareSection[T constraint](parameters T) (string, error) {
+ switch v := any(parameters).(type) {
+ case *params.Parameters:
+ return parametersToDeclares(*v), nil
+ case []*params.Parameter:
+ return parametersToDeclares(v), nil
case []table.ParameterOption:
- return internal.GenerateDeclareSection(table.NewQueryParameters(v...))
+ return parameterOptionsToDeclares(v), nil
case []sql.NamedArg:
- values, err := bind.Params(func() (newArgs []interface{}) {
- for i := range v {
- newArgs = append(newArgs, v[i])
- }
- return newArgs
- }()...)
- if err != nil {
- return "", xerrors.WithStackTrace(err)
- }
- return internal.GenerateDeclareSection(table.NewQueryParameters(values...))
+ return namedArgsToDeclares(v)
default:
return "", xerrors.WithStackTrace(fmt.Errorf("unsupported type: %T", v))
}
@@ -40,7 +37,7 @@ func GenerateDeclareSection[T *table.QueryParameters | []table.ParameterOption |
// ToYdbParam converts
//
// Deprecated: use testutil/QueryBind helper
-func ToYdbParam(param sql.NamedArg) (table.ParameterOption, error) {
+func ToYdbParam(param sql.NamedArg) (*params.Parameter, error) {
params, err := bind.Params(param)
if err != nil {
return nil, xerrors.WithStackTrace(err)
@@ -48,5 +45,54 @@ func ToYdbParam(param sql.NamedArg) (table.ParameterOption, error) {
if len(params) != 1 {
return nil, xerrors.WithStackTrace(fmt.Errorf("internal error: wrong parameters count: %v", params))
}
+
return params[0], nil
}
+
+func parametersToDeclares(v []*params.Parameter) string {
+ var (
+ buf = xstring.Buffer()
+ names = make([]string, 0, len(v))
+ declares = make(map[string]string, len(v))
+ )
+ defer buf.Free()
+
+ for _, p := range v {
+ name := p.Name()
+ names = append(names, name)
+ declares[name] = params.Declare(p)
+ }
+
+ sort.Strings(names)
+
+ for _, name := range names {
+ buf.WriteString(declares[name])
+ buf.WriteString(";\n")
+ }
+
+ return buf.String()
+}
+
+func parameterOptionsToDeclares(v []table.ParameterOption) string {
+ parameters := make([]*params.Parameter, len(v))
+ for i, p := range v {
+ parameters[i] = params.Named(p.Name(), p.Value())
+ }
+
+ return parametersToDeclares(parameters)
+}
+
+func namedArgsToDeclares(v []sql.NamedArg) (string, error) {
+ vv, err := bind.Params(func() (newArgs []interface{}) {
+ for i := range v {
+ newArgs = append(newArgs, v[i])
+ }
+
+ return newArgs
+ }()...)
+ if err != nil {
+ return "", xerrors.WithStackTrace(err)
+ }
+
+ return parametersToDeclares(vv), nil
+}
diff --git a/sugar/params_test.go b/sugar/params_test.go
index b3a6ee10c..8ef2d46bb 100644
--- a/sugar/params_test.go
+++ b/sugar/params_test.go
@@ -25,6 +25,7 @@ func TestGenerateDeclareSection(t *testing.T) {
}
}
sort.Strings(declares)
+
return declares
}
for _, tt := range []struct {
@@ -124,6 +125,7 @@ func TestGenerateDeclareSection_ParameterOption(t *testing.T) {
}
}
sort.Strings(declares)
+
return declares
}
for _, tt := range []struct {
@@ -230,6 +232,7 @@ func TestGenerateDeclareSection_NamedArg(t *testing.T) {
}
}
sort.Strings(declares)
+
return declares
}
for _, tt := range []struct {
diff --git a/sugar/path.go b/sugar/path.go
index 4de49c3fd..cc22e15aa 100644
--- a/sugar/path.go
+++ b/sugar/path.go
@@ -173,5 +173,6 @@ func RemoveRecursive(ctx context.Context, db dbFoRemoveRecursive, pathToRemove s
if !strings.HasPrefix(pathToRemove, db.Name()) {
pathToRemove = path.Join(db.Name(), pathToRemove)
}
+
return rmPath(0, pathToRemove)
}
diff --git a/sugar/result.go b/sugar/result.go
new file mode 100644
index 000000000..33c2339d9
--- /dev/null
+++ b/sugar/result.go
@@ -0,0 +1,83 @@
+package sugar
+
+import (
+ "context"
+ "errors"
+ "io"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/scanner"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/table/result/indexed"
+ "github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
+)
+
+type result struct {
+ r query.Result
+ rs query.ResultSet
+ row query.Row
+}
+
+func (r *result) NextResultSet(ctx context.Context) bool {
+ var err error
+ r.rs, err = r.r.NextResultSet(ctx)
+ if err != nil && errors.Is(err, io.EOF) {
+ return false
+ }
+
+ return err == nil && r.rs != nil && r.r.Err() == nil
+}
+
+func (r *result) NextRow() bool {
+ if r.rs == nil {
+ return false
+ }
+
+ var err error
+ r.row, err = r.rs.NextRow(context.Background())
+ if err != nil && errors.Is(err, io.EOF) {
+ return false
+ }
+
+ return r.row != nil && r.r.Err() == nil
+}
+
+func (r *result) Scan(indexedValues ...indexed.RequiredOrOptional) error {
+ values := make([]interface{}, 0, len(indexedValues))
+ for _, value := range indexedValues {
+ values = append(values, value)
+ }
+
+ return r.row.Scan(values...)
+}
+
+func (r *result) ScanNamed(namedValues ...named.Value) error {
+ values := make([]scanner.NamedDestination, 0, len(namedValues))
+ for i := range namedValues {
+ values = append(values, scanner.NamedRef(namedValues[i].Name, namedValues[i].Value))
+ }
+
+ return r.row.ScanNamed(values...)
+}
+
+func (r *result) ScanStruct(dst interface{}) error {
+ return r.row.ScanStruct(dst)
+}
+
+func (r *result) Err() error {
+ return r.r.Err()
+}
+
+func (r *result) Close() error {
+ return r.r.Close(context.Background())
+}
+
+// Result converts query.Result to iterable result for compatibility with table/result.Result usage
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+func Result(r query.Result) *result {
+ return &result{
+ r: r,
+ }
+}
diff --git a/table/example_test.go b/table/example_test.go
index c02fd1e5f..430c28f84 100644
--- a/table/example_test.go
+++ b/table/example_test.go
@@ -22,6 +22,7 @@ func Example_select() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -51,6 +52,7 @@ func Example_select() {
}
fmt.Printf("id=%v, myStr='%s'\n", id, myStr)
}
+
return res.Err() // return finally result error for auto-retry with driver
},
table.WithIdempotent(),
@@ -65,6 +67,7 @@ func Example_createTable() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -99,6 +102,7 @@ func Example_bulkUpsert() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -135,6 +139,7 @@ func Example_bulkUpsert() {
types.StructFieldValue("Message", types.TextValue(msg.Message)),
))
}
+
return s.BulkUpsert(ctx, "/local/bulk_upsert_example", types.ListValue(rows...))
},
table.WithIdempotent(),
@@ -149,6 +154,7 @@ func Example_alterTable() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -184,6 +190,7 @@ func Example_lazyTransaction() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx)
@@ -240,6 +247,7 @@ func Example_lazyTransaction() {
if err != nil {
return err
}
+
return result.Err()
},
table.WithIdempotent(),
@@ -254,6 +262,7 @@ func Example_bulkUpsertWithCompression() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -290,6 +299,7 @@ func Example_bulkUpsertWithCompression() {
types.StructFieldValue("Message", types.TextValue(msg.Message)),
))
}
+
return s.BulkUpsert(ctx, "/local/bulk_upsert_example", types.ListValue(rows...),
options.WithCallOptions(grpc.UseCompressor(gzip.Name)),
)
@@ -306,6 +316,7 @@ func Example_dataQueryWithCompression() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -339,6 +350,7 @@ func Example_dataQueryWithCompression() {
}
fmt.Printf("id=%v, myStr='%s'\n", id, myStr)
}
+
return res.Err() // return finally result error for auto-retry with driver
},
table.WithIdempotent(),
@@ -353,6 +365,7 @@ func Example_scanQueryWithCompression() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -386,6 +399,7 @@ func Example_scanQueryWithCompression() {
}
fmt.Printf("id=%v, myStr='%s'\n", id, myStr)
}
+
return res.Err() // return finally result error for auto-retry with driver
},
table.WithIdempotent(),
@@ -400,6 +414,7 @@ func Example_copyTables() {
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
fmt.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
diff --git a/table/options/models.go b/table/options/models.go
index 2f285ad02..4692d9d4a 100644
--- a/table/options/models.go
+++ b/table/options/models.go
@@ -9,8 +9,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/feature"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
type Column struct {
@@ -22,7 +22,7 @@ type Column struct {
func (c Column) toYDB(a *allocator.Allocator) *Ydb_Table.ColumnMeta {
return &Ydb_Table.ColumnMeta{
Name: c.Name,
- Type: value.TypeToYDB(c.Type, a),
+ Type: types.TypeToYDB(c.Type, a),
Family: c.Family,
}
}
@@ -43,15 +43,6 @@ type IndexDescription struct {
Type IndexType
}
-//nolint:unused
-func (i IndexDescription) toYDB() *Ydb_Table.TableIndexDescription {
- return &Ydb_Table.TableIndexDescription{
- Name: i.Name,
- IndexColumns: i.IndexColumns,
- Status: i.Status,
- }
-}
-
type Description struct {
Name string
Columns []Column
@@ -117,6 +108,7 @@ func (s StoragePool) toYDB() *Ydb_Table.StoragePool {
if s.Media == "" {
return nil
}
+
return &Ydb_Table.StoragePool{
Media: s.Media,
}
@@ -405,8 +397,8 @@ type (
)
type KeyRange struct {
- From types.Value
- To types.Value
+ From value.Value
+ To value.Value
}
func (kr KeyRange) String() string {
@@ -424,6 +416,7 @@ func (kr KeyRange) String() string {
buf.WriteString(kr.To.Yql())
}
buf.WriteString("]")
+
return buf.String()
}
@@ -463,6 +456,7 @@ func NewTTLSettings() TimeToLiveSettings {
func (ttl TimeToLiveSettings) ColumnDateType(columnName string) TimeToLiveSettings {
ttl.Mode = TimeToLiveModeDateType
ttl.ColumnName = columnName
+
return ttl
}
@@ -474,6 +468,7 @@ func (ttl TimeToLiveSettings) ColumnSeconds(columnName string) TimeToLiveSetting
ttl.Mode = TimeToLiveModeValueSinceUnixEpoch
ttl.ColumnName = columnName
ttl.ColumnUnit = unitToPointer(TimeToLiveUnitSeconds)
+
return ttl
}
@@ -481,6 +476,7 @@ func (ttl TimeToLiveSettings) ColumnMilliseconds(columnName string) TimeToLiveSe
ttl.Mode = TimeToLiveModeValueSinceUnixEpoch
ttl.ColumnName = columnName
ttl.ColumnUnit = unitToPointer(TimeToLiveUnitMilliseconds)
+
return ttl
}
@@ -488,6 +484,7 @@ func (ttl TimeToLiveSettings) ColumnMicroseconds(columnName string) TimeToLiveSe
ttl.Mode = TimeToLiveModeValueSinceUnixEpoch
ttl.ColumnName = columnName
ttl.ColumnUnit = unitToPointer(TimeToLiveUnitMicroseconds)
+
return ttl
}
@@ -495,11 +492,13 @@ func (ttl TimeToLiveSettings) ColumnNanoseconds(columnName string) TimeToLiveSet
ttl.Mode = TimeToLiveModeValueSinceUnixEpoch
ttl.ColumnName = columnName
ttl.ColumnUnit = unitToPointer(TimeToLiveUnitNanoseconds)
+
return ttl
}
func (ttl TimeToLiveSettings) ExpireAfter(expireAfter time.Duration) TimeToLiveSettings {
ttl.ExpireAfterSeconds = uint32(expireAfter.Seconds())
+
return ttl
}
diff --git a/table/options/options.go b/table/options/options.go
index 62a2a0818..db85556a7 100644
--- a/table/options/options.go
+++ b/table/options/options.go
@@ -6,8 +6,8 @@ import (
"google.golang.org/grpc"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
func WithShardKeyBounds() DescribeTableOption {
@@ -59,14 +59,14 @@ type column struct {
func (c column) ApplyAlterTableOption(d *AlterTableDesc, a *allocator.Allocator) {
d.AddColumns = append(d.AddColumns, &Ydb_Table.ColumnMeta{
Name: c.name,
- Type: value.TypeToYDB(c.typ, a),
+ Type: types.TypeToYDB(c.typ, a),
})
}
func (c column) ApplyCreateTableOption(d *CreateTableDesc, a *allocator.Allocator) {
d.Columns = append(d.Columns, &Ydb_Table.ColumnMeta{
Name: c.name,
- Type: value.TypeToYDB(c.typ, a),
+ Type: types.TypeToYDB(c.typ, a),
})
}
@@ -161,7 +161,9 @@ func (i index) ApplyAlterTableOption(d *AlterTableDesc, a *allocator.Allocator)
Name: i.name,
}
for _, opt := range i.opts {
- opt.ApplyIndexOption((*indexDesc)(x))
+ if opt != nil {
+ opt.ApplyIndexOption((*indexDesc)(x))
+ }
}
d.AddIndexes = append(d.AddIndexes, x)
}
@@ -171,7 +173,9 @@ func (i index) ApplyCreateTableOption(d *CreateTableDesc, a *allocator.Allocator
Name: i.name,
}
for _, opt := range i.opts {
- opt.ApplyIndexOption((*indexDesc)(x))
+ if opt != nil {
+ opt.ApplyIndexOption((*indexDesc)(x))
+ }
}
d.Indexes = append(d.Indexes, x)
}
@@ -304,7 +308,7 @@ func WithUniformPartitions(n uint64) Partitions {
return uniformPartitions(n)
}
-type explicitPartitions []types.Value
+type explicitPartitions []value.Value
func (e explicitPartitions) ApplyCreateTableOption(d *CreateTableDesc, a *allocator.Allocator) {
values := make([]*Ydb.TypedValue, len(e))
@@ -320,7 +324,7 @@ func (e explicitPartitions) ApplyCreateTableOption(d *CreateTableDesc, a *alloca
func (e explicitPartitions) isPartitions() {}
-func WithExplicitPartitions(splitPoints ...types.Value) Partitions {
+func WithExplicitPartitions(splitPoints ...value.Value) Partitions {
return explicitPartitions(splitPoints)
}
@@ -524,7 +528,7 @@ func WithPartitioningPolicyUniformPartitions(n uint64) PartitioningPolicyOption
}
// Deprecated: use WithExplicitPartitions instead
-func WithPartitioningPolicyExplicitPartitions(splitPoints ...types.Value) PartitioningPolicyOption {
+func WithPartitioningPolicyExplicitPartitions(splitPoints ...value.Value) PartitioningPolicyOption {
return func(p *partitioningPolicy, a *allocator.Allocator) {
values := make([]*Ydb.TypedValue, len(splitPoints))
for i := range values {
@@ -871,6 +875,7 @@ func WithCallOptions(opts ...grpc.CallOption) withCallOptions {
func WithCommit() ExecuteDataQueryOption {
return executeDataQueryOptionFunc(func(desc *ExecuteDataQueryDesc, a *allocator.Allocator) []grpc.CallOption {
desc.TxControl.CommitTx = true
+
return nil
})
}
@@ -879,6 +884,7 @@ func WithCommit() ExecuteDataQueryOption {
func WithIgnoreTruncated() ExecuteDataQueryOption {
return executeDataQueryOptionFunc(func(desc *ExecuteDataQueryDesc, a *allocator.Allocator) []grpc.CallOption {
desc.IgnoreTruncated = true
+
return nil
})
}
@@ -915,6 +921,7 @@ func withQueryCachePolicy(opts ...QueryCachePolicyOption) ExecuteDataQueryOption
opt((*queryCachePolicy)(d.QueryCachePolicy), a)
}
}
+
return nil
})
}
@@ -934,6 +941,7 @@ func WithCommitCollectStatsModeBasic() CommitTransactionOption {
func WithCollectStatsModeNone() ExecuteDataQueryOption {
return executeDataQueryOptionFunc(func(d *ExecuteDataQueryDesc, a *allocator.Allocator) []grpc.CallOption {
d.CollectStats = Ydb_Table.QueryStatsCollection_STATS_COLLECTION_NONE
+
return nil
})
}
@@ -941,6 +949,7 @@ func WithCollectStatsModeNone() ExecuteDataQueryOption {
func WithCollectStatsModeBasic() ExecuteDataQueryOption {
return executeDataQueryOptionFunc(func(d *ExecuteDataQueryDesc, a *allocator.Allocator) []grpc.CallOption {
d.CollectStats = Ydb_Table.QueryStatsCollection_STATS_COLLECTION_BASIC
+
return nil
})
}
@@ -969,6 +978,7 @@ var _ ExecuteScanQueryOption = executeScanQueryOptionFunc(nil)
func WithExecuteScanQueryMode(m ExecuteScanQueryRequestMode) ExecuteScanQueryOption {
return executeScanQueryOptionFunc(func(desc *ExecuteScanQueryDesc) []grpc.CallOption {
desc.Mode = m.toYDB()
+
return nil
})
}
@@ -999,6 +1009,7 @@ func (stats ExecuteScanQueryStatsType) toYDB() Ydb_Table.QueryStatsCollection_Mo
func WithExecuteScanQueryStats(stats ExecuteScanQueryStatsType) ExecuteScanQueryOption {
return executeScanQueryOptionFunc(func(desc *ExecuteScanQueryDesc) []grpc.CallOption {
desc.CollectStats = stats.toYDB()
+
return nil
})
}
@@ -1029,10 +1040,10 @@ type (
readOrderedOption struct{}
readSnapshotOption bool
readKeyRangeOption KeyRange
- readGreaterOrEqualOption struct{ types.Value }
- readLessOrEqualOption struct{ types.Value }
- readLessOption struct{ types.Value }
- readGreaterOption struct{ types.Value }
+ readGreaterOrEqualOption struct{ value.Value }
+ readLessOrEqualOption struct{ value.Value }
+ readLessOption struct{ value.Value }
+ readGreaterOption struct{ value.Value }
readRowLimitOption uint64
)
@@ -1126,19 +1137,19 @@ func ReadKeyRange(x KeyRange) ReadTableOption {
return readKeyRangeOption(x)
}
-func ReadGreater(x types.Value) ReadTableOption {
+func ReadGreater(x value.Value) ReadTableOption {
return readGreaterOption{x}
}
-func ReadGreaterOrEqual(x types.Value) ReadTableOption {
+func ReadGreaterOrEqual(x value.Value) ReadTableOption {
return readGreaterOrEqualOption{x}
}
-func ReadLess(x types.Value) ReadTableOption {
+func ReadLess(x value.Value) ReadTableOption {
return readLessOption{x}
}
-func ReadLessOrEqual(x types.Value) ReadTableOption {
+func ReadLessOrEqual(x value.Value) ReadTableOption {
return readLessOrEqualOption{x}
}
diff --git a/table/options/options_test.go b/table/options/options_test.go
index d702a8fb0..3b639ce6a 100644
--- a/table/options/options_test.go
+++ b/table/options/options_test.go
@@ -9,8 +9,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/feature"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
var abc = "abc"
@@ -24,7 +24,7 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- if req.Profile.PresetName != abc {
+ if req.GetProfile().GetPresetName() != abc {
t.Errorf("Preset is not as expected")
}
}
@@ -34,7 +34,7 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- if req.Profile.CompactionPolicy.PresetName != abc {
+ if req.GetProfile().GetCompactionPolicy().GetPresetName() != abc {
t.Errorf("Compaction policy is not as expected")
}
}
@@ -47,8 +47,8 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- p := req.Profile.PartitioningPolicy
- if p.PresetName != abc || p.AutoPartitioning != Ydb_Table.PartitioningPolicy_AUTO_SPLIT {
+ p := req.GetProfile().GetPartitioningPolicy()
+ if p.GetPresetName() != abc || p.GetAutoPartitioning() != Ydb_Table.PartitioningPolicy_AUTO_SPLIT {
t.Errorf("Partitioning policy is not as expected")
}
}
@@ -58,26 +58,26 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- if p, ok := req.Partitions.(*Ydb_Table.CreateTableRequest_UniformPartitions); !ok || p.UniformPartitions != 3 {
+ if p, ok := req.GetPartitions().(*Ydb_Table.CreateTableRequest_UniformPartitions); !ok || p.UniformPartitions != 3 {
t.Errorf("Uniform partitioning policy is not as expected")
}
}
{
opt := WithPartitions(
WithExplicitPartitions(
- types.Int64Value(1),
+ value.Int64Value(1),
),
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- p, ok := req.Partitions.(*Ydb_Table.CreateTableRequest_PartitionAtKeys)
+ p, ok := req.GetPartitions().(*Ydb_Table.CreateTableRequest_PartitionAtKeys)
if !ok {
t.Errorf("Explicitly partitioning policy is not as expected")
} else {
require.Equal(
t,
- []*Ydb.TypedValue{value.ToYDB(types.Int64Value(1), a)},
- p.PartitionAtKeys.SplitPoints,
+ []*Ydb.TypedValue{value.ToYDB(value.Int64Value(1), a)},
+ p.PartitionAtKeys.GetSplitPoints(),
)
}
}
@@ -87,7 +87,7 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- if req.Profile.ExecutionPolicy.PresetName != abc {
+ if req.GetProfile().GetExecutionPolicy().GetPresetName() != abc {
t.Errorf("Execution policy is not as expected")
}
}
@@ -102,11 +102,11 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- p := req.Profile.ReplicationPolicy
- if p.PresetName != abc ||
- p.ReplicasCount != 3 ||
- p.CreatePerAvailabilityZone != Ydb.FeatureFlag_ENABLED ||
- p.AllowPromotion != Ydb.FeatureFlag_DISABLED {
+ p := req.GetProfile().GetReplicationPolicy()
+ if p.GetPresetName() != abc ||
+ p.GetReplicasCount() != 3 ||
+ p.GetCreatePerAvailabilityZone() != Ydb.FeatureFlag_ENABLED ||
+ p.GetAllowPromotion() != Ydb.FeatureFlag_DISABLED {
t.Errorf("Replication policy is not as expected")
}
}
@@ -116,7 +116,7 @@ func TestSessionOptionsProfile(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- if req.Profile.CachingPolicy.PresetName != abc {
+ if req.GetProfile().GetCachingPolicy().GetPresetName() != abc {
t.Errorf("Caching policy is not as expected")
}
}
@@ -138,13 +138,13 @@ func TestStoragePolicyOptions(t *testing.T) {
)
req := Ydb_Table.CreateTableRequest{}
opt.ApplyCreateTableOption((*CreateTableDesc)(&req), a)
- p := req.Profile.StoragePolicy
- if p.PresetName != abc ||
- p.Syslog.Media != "any1" ||
- p.Log.Media != "any2" ||
- p.Data.Media != "any3" ||
- p.External.Media != "any4" ||
- p.KeepInMemory != Ydb.FeatureFlag_ENABLED {
+ p := req.GetProfile().GetStoragePolicy()
+ if p.GetPresetName() != abc ||
+ p.GetSyslog().GetMedia() != "any1" ||
+ p.GetLog().GetMedia() != "any2" ||
+ p.GetData().GetMedia() != "any3" ||
+ p.GetExternal().GetMedia() != "any4" ||
+ p.GetKeepInMemory() != Ydb.FeatureFlag_ENABLED {
t.Errorf("Storage policy is not as expected")
}
}
@@ -154,27 +154,27 @@ func TestAlterTableOptions(t *testing.T) {
a := allocator.New()
defer a.Free()
{
- opt := WithAddColumn("a", types.TypeBool)
+ opt := WithAddColumn("a", types.Bool)
req := Ydb_Table.AlterTableRequest{}
opt.ApplyAlterTableOption((*AlterTableDesc)(&req), a)
- if len(req.AddColumns) != 1 ||
- req.AddColumns[0].Name != "a" {
+ if len(req.GetAddColumns()) != 1 ||
+ req.GetAddColumns()[0].GetName() != "a" {
t.Errorf("Alter table options is not as expected")
}
}
{
column := Column{
Name: "a",
- Type: types.TypeBool,
+ Type: types.Bool,
Family: "b",
}
opt := WithAddColumnMeta(column)
req := Ydb_Table.AlterTableRequest{}
opt.ApplyAlterTableOption((*AlterTableDesc)(&req), a)
- if len(req.AddColumns) != 1 ||
- req.AddColumns[0].Name != column.Name ||
- req.AddColumns[0].Type != value.TypeToYDB(column.Type, a) ||
- req.AddColumns[0].Family != column.Family {
+ if len(req.GetAddColumns()) != 1 ||
+ req.GetAddColumns()[0].GetName() != column.Name ||
+ req.GetAddColumns()[0].GetType() != types.TypeToYDB(column.Type, a) ||
+ req.GetAddColumns()[0].GetFamily() != column.Family {
t.Errorf("Alter table options is not as expected")
}
}
@@ -182,8 +182,8 @@ func TestAlterTableOptions(t *testing.T) {
opt := WithDropColumn("a")
req := Ydb_Table.AlterTableRequest{}
opt.ApplyAlterTableOption((*AlterTableDesc)(&req), a)
- if len(req.DropColumns) != 1 ||
- req.DropColumns[0] != "a" {
+ if len(req.GetDropColumns()) != 1 ||
+ req.GetDropColumns()[0] != "a" {
t.Errorf("Alter table options is not as expected")
}
}
@@ -199,11 +199,11 @@ func TestAlterTableOptions(t *testing.T) {
opt := WithAlterColumnFamilies(cf)
req := Ydb_Table.AlterTableRequest{}
opt.ApplyAlterTableOption((*AlterTableDesc)(&req), a)
- if len(req.AddColumnFamilies) != 1 ||
- req.AddColumnFamilies[0].Name != cf.Name ||
- req.AddColumnFamilies[0].Data.Media != cf.Data.Media ||
- req.AddColumnFamilies[0].Compression != cf.Compression.toYDB() ||
- req.AddColumnFamilies[0].KeepInMemory != cf.KeepInMemory.ToYDB() {
+ if len(req.GetAddColumnFamilies()) != 1 ||
+ req.GetAddColumnFamilies()[0].GetName() != cf.Name ||
+ req.GetAddColumnFamilies()[0].GetData().GetMedia() != cf.Data.Media ||
+ req.GetAddColumnFamilies()[0].GetCompression() != cf.Compression.toYDB() ||
+ req.GetAddColumnFamilies()[0].GetKeepInMemory() != cf.KeepInMemory.ToYDB() {
t.Errorf("Alter table options is not as expected")
}
}
@@ -215,11 +215,11 @@ func TestAlterTableOptions(t *testing.T) {
opt := WithAlterColumnFamilies(cf)
req := Ydb_Table.AlterTableRequest{}
opt.ApplyAlterTableOption((*AlterTableDesc)(&req), a)
- if len(req.AddColumnFamilies) != 1 ||
- req.AddColumnFamilies[0].Name != cf.Name ||
- req.AddColumnFamilies[0].Data != nil ||
- req.AddColumnFamilies[0].Compression != cf.Compression.toYDB() ||
- req.AddColumnFamilies[0].KeepInMemory != Ydb.FeatureFlag_STATUS_UNSPECIFIED {
+ if len(req.GetAddColumnFamilies()) != 1 ||
+ req.GetAddColumnFamilies()[0].GetName() != cf.Name ||
+ req.GetAddColumnFamilies()[0].GetData() != nil ||
+ req.GetAddColumnFamilies()[0].GetCompression() != cf.Compression.toYDB() ||
+ req.GetAddColumnFamilies()[0].GetKeepInMemory() != Ydb.FeatureFlag_STATUS_UNSPECIFIED {
t.Errorf("Alter table options is not as expected")
}
}
diff --git a/table/result/indexed/indexed.go b/table/result/indexed/indexed.go
index f92b205c5..af8a637d6 100644
--- a/table/result/indexed/indexed.go
+++ b/table/result/indexed/indexed.go
@@ -27,7 +27,7 @@ type Optional interface{}
// RequiredOrOptional is a type scan destination of ydb values
// This is a proxy type for preparing go1.18 type set constrains such as
//
-// type Value interface {
+// type valueType interface {
// Required | Optional
// }
type RequiredOrOptional interface{}
diff --git a/table/result/named/named.go b/table/result/named/named.go
index 586a5d077..2d7295a3a 100644
--- a/table/result/named/named.go
+++ b/table/result/named/named.go
@@ -24,6 +24,7 @@ func Optional(columnName string, destination interface{}) Value {
if columnName == "" {
panic("columnName must be not empty")
}
+
return Value{
Name: columnName,
Value: destination,
@@ -38,6 +39,7 @@ func Required(columnName string, destinationValueReference interface{}) Value {
if columnName == "" {
panic("columnName must be not empty")
}
+
return Value{
Name: columnName,
Value: destinationValueReference,
@@ -53,6 +55,7 @@ func OptionalWithDefault(columnName string, destinationValueReference interface{
if columnName == "" {
panic("columnName must be not empty")
}
+
return Value{
Name: columnName,
Value: destinationValueReference,
diff --git a/table/result/result.go b/table/result/result.go
index c8514187d..e82860f3d 100644
--- a/table/result/result.go
+++ b/table/result/result.go
@@ -91,7 +91,7 @@ type BaseResult interface {
// string
// time.Time
// time.Duration
- // ydb.Value
+ // ydb.valueType
// For custom types implement sql.Scanner or json.Unmarshaler interface.
// For optional types use double pointer construction.
// For unknown types use interface types.
diff --git a/table/table.go b/table/table.go
index 45b81f687..6d2305a1e 100644
--- a/table/table.go
+++ b/table/table.go
@@ -2,20 +2,17 @@ package table
import (
"context"
- "sort"
"time"
- "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
@@ -144,7 +141,7 @@ type Session interface {
ctx context.Context,
tx *TransactionControl,
query string,
- params *QueryParameters,
+ params *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (txr Transaction, r result.Result, err error)
@@ -167,21 +164,21 @@ type Session interface {
StreamExecuteScanQuery(
ctx context.Context,
query string,
- params *QueryParameters,
+ params *params.Parameters,
opts ...options.ExecuteScanQueryOption,
) (_ result.StreamResult, err error)
BulkUpsert(
ctx context.Context,
table string,
- rows types.Value,
+ rows value.Value,
opts ...options.BulkUpsertOption,
) (err error)
ReadRows(
ctx context.Context,
path string,
- keys types.Value,
+ keys value.Value,
opts ...options.ReadRowsOption,
) (_ result.Result, err error)
@@ -203,6 +200,7 @@ func (t *TransactionSettings) Settings() *Ydb_Table.TransactionSettings {
if t == nil {
return nil
}
+
return &t.settings
}
@@ -242,13 +240,13 @@ type TransactionActor interface {
Execute(
ctx context.Context,
query string,
- params *QueryParameters,
+ params *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (result.Result, error)
ExecuteStatement(
ctx context.Context,
stmt Statement,
- params *QueryParameters,
+ params *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (result.Result, error)
}
@@ -269,7 +267,7 @@ type Statement interface {
Execute(
ctx context.Context,
tx *TransactionControl,
- params *QueryParameters,
+ params *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (txr Transaction, r result.Result, err error)
NumInput() int
@@ -302,6 +300,7 @@ func TxSettings(opts ...TxOption) *TransactionSettings {
opt((*txDesc)(&s.settings))
}
}
+
return s
}
@@ -394,6 +393,7 @@ func (t *TransactionControl) Desc() *Ydb_Table.TransactionControl {
if t == nil {
return nil
}
+
return &t.desc
}
@@ -405,6 +405,7 @@ func TxControl(opts ...TxControlOption) *TransactionControl {
opt((*txControlDesc)(&c.desc))
}
}
+
return c
}
@@ -451,107 +452,22 @@ func SnapshotReadOnlyTxControl() *TransactionControl {
// QueryParameters
type (
- queryParams map[string]types.Value
- ParameterOption interface {
- Name() string
- Value() types.Value
- }
- parameterOption struct {
- name string
- value types.Value
- }
- QueryParameters struct {
- m queryParams
- }
+ ParameterOption = params.NamedValue
+ QueryParameters = params.Parameters
)
-func (p parameterOption) Name() string {
- return p.name
-}
-
-func (p parameterOption) Value() types.Value {
- return p.value
-}
-
-func (qp queryParams) ToYDB(a *allocator.Allocator) map[string]*Ydb.TypedValue {
- if qp == nil {
- return nil
- }
- params := make(map[string]*Ydb.TypedValue, len(qp))
- for k, v := range qp {
- params[k] = value.ToYDB(v, a)
- }
- return params
-}
-
-func (q *QueryParameters) Params() queryParams {
- if q == nil {
- return nil
- }
- return q.m
-}
-
-func (q *QueryParameters) Count() int {
- if q == nil {
- return 0
- }
- return len(q.m)
-}
-
-func (q *QueryParameters) Each(it func(name string, v types.Value)) {
- if q == nil {
- return
- }
- for key, v := range q.m {
- it(key, v)
- }
-}
-
-func (q *QueryParameters) names() []string {
- if q == nil {
- return nil
- }
- names := make([]string, 0, len(q.m))
- for k := range q.m {
- names = append(names, k)
- }
- sort.Strings(names)
- return names
-}
-
-func (q *QueryParameters) String() string {
- buffer := xstring.Buffer()
- defer buffer.Free()
-
- buffer.WriteByte('{')
- for i, name := range q.names() {
- if i != 0 {
- buffer.WriteByte(',')
- }
- buffer.WriteByte('"')
- buffer.WriteString(name)
- buffer.WriteString("\":")
- buffer.WriteString(q.m[name].Yql())
- }
- buffer.WriteByte('}')
- return buffer.String()
-}
-
func NewQueryParameters(opts ...ParameterOption) *QueryParameters {
- q := &QueryParameters{
- m: make(queryParams, len(opts)),
+ qp := QueryParameters(make([]*params.Parameter, len(opts)))
+ for i, opt := range opts {
+ if opt != nil {
+ qp[i] = params.Named(opt.Name(), opt.Value())
+ }
}
- q.Add(opts...)
- return q
-}
-func (q *QueryParameters) Add(params ...ParameterOption) {
- for _, param := range params {
- q.m[param.Name()] = param.Value()
- }
+ return &qp
}
-func ValueParam(name string, v types.Value) ParameterOption {
+func ValueParam(name string, v value.Value) ParameterOption {
switch len(name) {
case 0:
panic("empty name")
@@ -560,10 +476,8 @@ func ValueParam(name string, v types.Value) ParameterOption {
name = "$" + name
}
}
- return ¶meterOption{
- name: name,
- value: v,
- }
+
+ return params.Named(name, v)
}
type Options struct {
diff --git a/table/types/cast.go b/table/types/cast.go
index 574e960fb..71d8476ea 100644
--- a/table/types/cast.go
+++ b/table/types/cast.go
@@ -15,6 +15,7 @@ func CastTo(v Value, dst interface{}) error {
if v == nil {
return xerrors.WithStackTrace(errNilValue)
}
+
return value.CastTo(v, dst)
}
@@ -26,6 +27,7 @@ func IsOptional(t Type) (isOptional bool, innerType Type) {
}); isOptional {
return isOptional, optionalType.InnerType()
}
+
return false, nil
}
@@ -38,6 +40,7 @@ func ToDecimal(v Value) (*Decimal, error) {
Scale: valuer.Scale(),
}, nil
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf("value type '%s' is not decimal type", v.Type().Yql()))
}
@@ -48,6 +51,7 @@ func ListItems(v Value) ([]Value, error) {
}); has {
return vv.ListItems(), nil
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf("cannot get list items from '%s'", v.Type().Yql()))
}
@@ -58,6 +62,7 @@ func TupleItems(v Value) ([]Value, error) {
}); has {
return vv.TupleItems(), nil
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf("cannot get tuple items from '%s'", v.Type().Yql()))
}
@@ -68,6 +73,7 @@ func StructFields(v Value) (map[string]Value, error) {
}); has {
return vv.StructFields(), nil
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf("cannot get struct fields from '%s'", v.Type().Yql()))
}
@@ -78,8 +84,10 @@ func VariantValue(v Value) (name string, idx uint32, _ Value, _ error) {
Value() Value
}); has {
name, idx := vv.Variant()
+
return name, idx, vv.Value(), nil
}
+
return "", 0, nil, xerrors.WithStackTrace(fmt.Errorf("cannot get variant value from '%s'", v.Type().Yql()))
}
@@ -97,5 +105,6 @@ func DictValues(v Value) (map[Value]Value, error) {
}); has {
return vv.DictValues(), nil
}
+
return nil, xerrors.WithStackTrace(fmt.Errorf("cannot get dict values from '%s'", v.Type().Yql()))
}
diff --git a/table/types/types.go b/table/types/types.go
index a9f587578..cca6b5c09 100644
--- a/table/types/types.go
+++ b/table/types/types.go
@@ -2,37 +2,36 @@ package types
import (
"bytes"
- "io"
- "time"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/scanner"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
)
// Type describes YDB data types.
-type Type = value.Type
+type Type = types.Type
// Equal checks for type equivalence
func Equal(lhs, rhs Type) bool {
- return value.TypesEqual(lhs, rhs)
+ return types.Equal(lhs, rhs)
}
func List(t Type) Type {
- return value.List(t)
+ return types.NewList(t)
}
func Tuple(elems ...Type) Type {
- return value.Tuple(elems...)
+ return types.NewTuple(elems...)
}
type tStructType struct {
- fields []value.StructField
+ fields []types.StructField
}
type StructOption func(*tStructType)
func StructField(name string, t Type) StructOption {
return func(s *tStructType) {
- s.fields = append(s.fields, value.StructField{
+ s.fields = append(s.fields, types.StructField{
Name: name,
T: t,
})
@@ -46,11 +45,12 @@ func Struct(opts ...StructOption) Type {
opt(&s)
}
}
- return value.Struct(s.fields...)
+
+ return types.NewStruct(s.fields...)
}
func Dict(k, v Type) Type {
- return value.Dict(k, v)
+ return types.NewDict(k, v)
}
func VariantStruct(opts ...StructOption) Type {
@@ -60,201 +60,72 @@ func VariantStruct(opts ...StructOption) Type {
opt(&s)
}
}
- return value.VariantStruct(s.fields...)
+
+ return types.NewVariantStruct(s.fields...)
}
func VariantTuple(elems ...Type) Type {
- return value.VariantTuple(elems...)
+ return types.NewVariantTuple(elems...)
}
func Void() Type {
- return value.Void()
+ return types.NewVoid()
}
func Optional(t Type) Type {
- return value.Optional(t)
+ return types.NewOptional(t)
}
var DefaultDecimal = DecimalType(22, 9)
func DecimalType(precision, scale uint32) Type {
- return value.Decimal(precision, scale)
+ return types.NewDecimal(precision, scale)
}
func DecimalTypeFromDecimal(d *Decimal) Type {
- return value.Decimal(d.Precision, d.Scale)
+ return types.NewDecimal(d.Precision, d.Scale)
}
// Primitive types known by YDB.
const (
- TypeUnknown = value.TypeUnknown
- TypeBool = value.TypeBool
- TypeInt8 = value.TypeInt8
- TypeUint8 = value.TypeUint8
- TypeInt16 = value.TypeInt16
- TypeUint16 = value.TypeUint16
- TypeInt32 = value.TypeInt32
- TypeUint32 = value.TypeUint32
- TypeInt64 = value.TypeInt64
- TypeUint64 = value.TypeUint64
- TypeFloat = value.TypeFloat
- TypeDouble = value.TypeDouble
- TypeDate = value.TypeDate
- TypeDatetime = value.TypeDatetime
- TypeTimestamp = value.TypeTimestamp
- TypeInterval = value.TypeInterval
- TypeTzDate = value.TypeTzDate
- TypeTzDatetime = value.TypeTzDatetime
- TypeTzTimestamp = value.TypeTzTimestamp
- TypeString = value.TypeBytes
- TypeBytes = value.TypeBytes
- TypeUTF8 = value.TypeText
- TypeText = value.TypeText
- TypeYSON = value.TypeYSON
- TypeJSON = value.TypeJSON
- TypeUUID = value.TypeUUID
- TypeJSONDocument = value.TypeJSONDocument
- TypeDyNumber = value.TypeDyNumber
+ TypeUnknown = types.Unknown
+ TypeBool = types.Bool
+ TypeInt8 = types.Int8
+ TypeUint8 = types.Uint8
+ TypeInt16 = types.Int16
+ TypeUint16 = types.Uint16
+ TypeInt32 = types.Int32
+ TypeUint32 = types.Uint32
+ TypeInt64 = types.Int64
+ TypeUint64 = types.Uint64
+ TypeFloat = types.Float
+ TypeDouble = types.Double
+ TypeDate = types.Date
+ TypeDatetime = types.Datetime
+ TypeTimestamp = types.Timestamp
+ TypeInterval = types.Interval
+ TypeTzDate = types.TzDate
+ TypeTzDatetime = types.TzDatetime
+ TypeTzTimestamp = types.TzTimestamp
+ TypeString = types.Bytes
+ TypeBytes = types.Bytes
+ TypeUTF8 = types.Text
+ TypeText = types.Text
+ TypeYSON = types.YSON
+ TypeJSON = types.JSON
+ TypeUUID = types.UUID
+ TypeJSONDocument = types.JSONDocument
+ TypeDyNumber = types.DyNumber
)
// WriteTypeStringTo writes ydb type string representation into buffer
//
// Deprecated: use types.Type.Yql() instead
-func WriteTypeStringTo(buf *bytes.Buffer, t Type) {
+func WriteTypeStringTo(buf *bytes.Buffer, t Type) { //nolint: interfacer
buf.WriteString(t.Yql())
}
-// RawValue scanning non-primitive yql types or for own implementation scanner native API
-type RawValue interface {
- Path() string
- WritePathTo(w io.Writer) (n int64, err error)
- Type() Type
- Bool() (v bool)
- Int8() (v int8)
- Uint8() (v uint8)
- Int16() (v int16)
- Uint16() (v uint16)
- Int32() (v int32)
- Uint32() (v uint32)
- Int64() (v int64)
- Uint64() (v uint64)
- Float() (v float32)
- Double() (v float64)
- Date() (v time.Time)
- Datetime() (v time.Time)
- Timestamp() (v time.Time)
- Interval() (v time.Duration)
- TzDate() (v time.Time)
- TzDatetime() (v time.Time)
- TzTimestamp() (v time.Time)
- String() (v []byte)
- UTF8() (v string)
- YSON() (v []byte)
- JSON() (v []byte)
- UUID() (v [16]byte)
- JSONDocument() (v []byte)
- DyNumber() (v string)
- Value() Value
-
- // Any returns any primitive or optional value.
- // Currently, it may return one of these types:
- //
- // bool
- // int8
- // uint8
- // int16
- // uint16
- // int32
- // uint32
- // int64
- // uint64
- // float32
- // float64
- // []byte
- // string
- // [16]byte
- //
- Any() interface{}
-
- // Unwrap unwraps current item under scan interpreting it as Optional types.
- Unwrap()
- AssertType(t Type) bool
- IsNull() bool
- IsOptional() bool
-
- // ListIn interprets current item under scan as a ydb's list.
- // It returns the size of the nested items.
- // If current item under scan is not a list types, it returns -1.
- ListIn() (size int)
-
- // ListItem selects current item i-th element as an item to scan.
- // ListIn() must be called before.
- ListItem(i int)
-
- // ListOut leaves list entered before by ListIn() call.
- ListOut()
-
- // TupleIn interprets current item under scan as a ydb's tuple.
- // It returns the size of the nested items.
- TupleIn() (size int)
-
- // TupleItem selects current item i-th element as an item to scan.
- // Note that TupleIn() must be called before.
- // It panics if it is out of bounds.
- TupleItem(i int)
-
- // TupleOut leaves tuple entered before by TupleIn() call.
- TupleOut()
-
- // StructIn interprets current item under scan as a ydb's struct.
- // It returns the size of the nested items – the struct fields values.
- // If there is no current item under scan it returns -1.
- StructIn() (size int)
-
- // StructField selects current item i-th field value as an item to scan.
- // Note that StructIn() must be called before.
- // It panics if i is out of bounds.
- StructField(i int) (name string)
-
- // StructOut leaves struct entered before by StructIn() call.
- StructOut()
-
- // DictIn interprets current item under scan as a ydb's dict.
- // It returns the size of the nested items pairs.
- // If there is no current item under scan it returns -1.
- DictIn() (size int)
-
- // DictKey selects current item i-th pair key as an item to scan.
- // Note that DictIn() must be called before.
- // It panics if i is out of bounds.
- DictKey(i int)
-
- // DictPayload selects current item i-th pair value as an item to scan.
- // Note that DictIn() must be called before.
- // It panics if i is out of bounds.
- DictPayload(i int)
-
- // DictOut leaves dict entered before by DictIn() call.
- DictOut()
-
- // Variant unwraps current item under scan interpreting it as Variant types.
- // It returns non-empty name of a field that is filled for struct-based
- // variant.
- // It always returns an index of filled field of a Type.
- Variant() (name string, index uint32)
-
- // Decimal returns decimal value represented by big-endian 128 bit signed integer.
- Decimal(t Type) (v [16]byte)
-
- // UnwrapDecimal returns decimal value represented by big-endian 128 bit signed
- // integer and its types information.
- UnwrapDecimal() Decimal
- IsDecimal() bool
- Err() error
-}
-
-// Scanner scanning raw ydb types
-type Scanner interface {
- // UnmarshalYDB must be implemented on client-side for unmarshal raw ydb value.
- UnmarshalYDB(raw RawValue) error
-}
+type (
+ RawValue = scanner.RawValue
+ Scanner = scanner.Scanner
+)
diff --git a/table/types/types_test.go b/table/types/types_test.go
deleted file mode 100644
index 9d4d46c4d..000000000
--- a/table/types/types_test.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package types
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestEqual(t *testing.T) {
- tests := []struct {
- lhs Type
- rhs Type
- equal bool
- }{
- {
- TypeBool,
- TypeBool,
- true,
- },
- {
- TypeBool,
- TypeText,
- false,
- },
- {
- TypeText,
- TypeText,
- true,
- },
- {
- Optional(TypeBool),
- Optional(TypeBool),
- true,
- },
- {
- Optional(TypeBool),
- Optional(TypeText),
- false,
- },
- {
- Optional(TypeText),
- Optional(TypeText),
- true,
- },
- }
- for _, tt := range tests {
- t.Run("", func(t *testing.T) {
- if equal := Equal(tt.lhs, tt.rhs); equal != tt.equal {
- t.Errorf("Equal(%s, %s) = %v, want %v", tt.lhs, tt.rhs, equal, tt.equal)
- }
- })
- }
-}
-
-func TestOptionalInnerType(t *testing.T) {
- tests := []struct {
- src Type
- innerType Type
- isOptional bool
- }{
- {
- TypeBool,
- nil,
- false,
- },
- {
- TypeText,
- nil,
- false,
- },
- {
- Optional(TypeBool),
- TypeBool,
- true,
- },
- {
- Optional(TypeText),
- TypeText,
- true,
- },
- {
- Optional(Tuple(TypeText, TypeBool, TypeUint64, Optional(TypeInt64))),
- Tuple(TypeText, TypeBool, TypeUint64, Optional(TypeInt64)),
- true,
- },
- }
- for _, tt := range tests {
- t.Run("", func(t *testing.T) {
- optional, isOptional := tt.src.(interface {
- IsOptional()
- InnerType() Type
- })
- require.Equal(t, tt.isOptional, isOptional)
- var innerType Type
- if isOptional {
- innerType = optional.InnerType()
- }
- if tt.innerType == nil {
- require.Nil(t, innerType)
- } else {
- require.True(t, Equal(tt.innerType, innerType))
- }
- })
- }
-}
diff --git a/table/types/value.go b/table/types/value.go
index f0d730287..9249c4e3c 100644
--- a/table/types/value.go
+++ b/table/types/value.go
@@ -1,7 +1,6 @@
package types
import (
- "fmt"
"math/big"
"time"
@@ -174,20 +173,7 @@ func ZeroValue(t Type) Value { return value.ZeroValue(t) }
func OptionalValue(v Value) Value { return value.OptionalValue(v) }
// Decimal supported in scanner API
-type Decimal struct {
- Bytes [16]byte
- Precision uint32
- Scale uint32
-}
-
-func (d *Decimal) String() string {
- v := decimal.FromInt128(d.Bytes, d.Precision, d.Scale)
- return decimal.Format(v, d.Precision, d.Scale)
-}
-
-func (d *Decimal) BigInt() *big.Int {
- return decimal.FromInt128(d.Bytes, d.Precision, d.Scale)
-}
+type Decimal = decimal.Decimal
// DecimalValue creates decimal value of given types t and value v.
// Note that Decimal.Bytes interpreted as big-endian int128.
@@ -230,6 +216,7 @@ func StructValue(opts ...StructValueOption) Value {
opt(&p)
}
}
+
return value.StructValue(p.fields...)
}
@@ -252,6 +239,7 @@ func DictValue(opts ...DictValueOption) Value {
opt(&p)
}
}
+
return value.DictValue(p.fields...)
}
@@ -264,440 +252,171 @@ func VariantValueTuple(v Value, i uint32, variantT Type) Value {
}
func NullableBoolValue(v *bool) Value {
- if v == nil {
- return NullValue(TypeBool)
- }
- return OptionalValue(BoolValue(*v))
+ return value.NullableBoolValue(v)
}
func NullableInt8Value(v *int8) Value {
- if v == nil {
- return NullValue(TypeInt8)
- }
- return OptionalValue(Int8Value(*v))
+ return value.NullableInt8Value(v)
}
func NullableInt16Value(v *int16) Value {
- if v == nil {
- return NullValue(TypeInt16)
- }
- return OptionalValue(Int16Value(*v))
+ return value.NullableInt16Value(v)
}
func NullableInt32Value(v *int32) Value {
- if v == nil {
- return NullValue(TypeInt32)
- }
- return OptionalValue(Int32Value(*v))
+ return value.NullableInt32Value(v)
}
func NullableInt64Value(v *int64) Value {
- if v == nil {
- return NullValue(TypeInt64)
- }
- return OptionalValue(Int64Value(*v))
+ return value.NullableInt64Value(v)
}
func NullableUint8Value(v *uint8) Value {
- if v == nil {
- return NullValue(TypeUint8)
- }
- return OptionalValue(Uint8Value(*v))
+ return value.NullableUint8Value(v)
}
func NullableUint16Value(v *uint16) Value {
- if v == nil {
- return NullValue(TypeUint16)
- }
- return OptionalValue(Uint16Value(*v))
+ return value.NullableUint16Value(v)
}
func NullableUint32Value(v *uint32) Value {
- if v == nil {
- return NullValue(TypeUint32)
- }
- return OptionalValue(Uint32Value(*v))
+ return value.NullableUint32Value(v)
}
func NullableUint64Value(v *uint64) Value {
- if v == nil {
- return NullValue(TypeUint64)
- }
- return OptionalValue(Uint64Value(*v))
+ return value.NullableUint64Value(v)
}
func NullableFloatValue(v *float32) Value {
- if v == nil {
- return NullValue(TypeFloat)
- }
- return OptionalValue(FloatValue(*v))
+ return value.NullableFloatValue(v)
}
func NullableDoubleValue(v *float64) Value {
- if v == nil {
- return NullValue(TypeDouble)
- }
- return OptionalValue(DoubleValue(*v))
+ return value.NullableDoubleValue(v)
}
func NullableDateValue(v *uint32) Value {
- if v == nil {
- return NullValue(TypeDate)
- }
- return OptionalValue(DateValue(*v))
+ return value.NullableDateValue(v)
}
func NullableDateValueFromTime(v *time.Time) Value {
- if v == nil {
- return NullValue(TypeDate)
- }
- return OptionalValue(DateValueFromTime(*v))
+ return value.NullableDateValueFromTime(v)
}
func NullableDatetimeValue(v *uint32) Value {
- if v == nil {
- return NullValue(TypeDatetime)
- }
- return OptionalValue(DatetimeValue(*v))
+ return value.NullableDatetimeValue(v)
}
func NullableDatetimeValueFromTime(v *time.Time) Value {
- if v == nil {
- return NullValue(TypeDatetime)
- }
- return OptionalValue(DatetimeValueFromTime(*v))
+ return value.NullableDatetimeValueFromTime(v)
}
func NullableTzDateValue(v *string) Value {
- if v == nil {
- return NullValue(TypeTzDate)
- }
- return OptionalValue(TzDateValue(*v))
+ return value.NullableTzDateValue(v)
}
func NullableTzDateValueFromTime(v *time.Time) Value {
- if v == nil {
- return NullValue(TypeTzDate)
- }
- return OptionalValue(TzDateValueFromTime(*v))
+ return value.NullableTzDateValueFromTime(v)
}
func NullableTzDatetimeValue(v *string) Value {
- if v == nil {
- return NullValue(TypeTzDatetime)
- }
- return OptionalValue(TzDatetimeValue(*v))
+ return value.NullableTzDatetimeValue(v)
}
func NullableTzDatetimeValueFromTime(v *time.Time) Value {
- if v == nil {
- return NullValue(TypeTzDatetime)
- }
- return OptionalValue(TzDatetimeValueFromTime(*v))
+ return value.NullableTzDatetimeValueFromTime(v)
}
func NullableTimestampValue(v *uint64) Value {
- if v == nil {
- return NullValue(TypeTimestamp)
- }
- return OptionalValue(TimestampValue(*v))
+ return value.NullableTimestampValue(v)
}
func NullableTimestampValueFromTime(v *time.Time) Value {
- if v == nil {
- return NullValue(TypeTimestamp)
- }
- return OptionalValue(TimestampValueFromTime(*v))
+ return value.NullableTimestampValueFromTime(v)
}
func NullableTzTimestampValue(v *string) Value {
- if v == nil {
- return NullValue(TypeTzTimestamp)
- }
- return OptionalValue(TzTimestampValue(*v))
+ return value.NullableTzTimestampValue(v)
}
func NullableTzTimestampValueFromTime(v *time.Time) Value {
- if v == nil {
- return NullValue(TypeTzTimestamp)
- }
- return OptionalValue(TzTimestampValueFromTime(*v))
+ return value.NullableTzTimestampValueFromTime(v)
}
// NullableIntervalValue makes Value which maybe nil or valued
//
// Deprecated: use NullableIntervalValueFromMicroseconds instead
func NullableIntervalValue(v *int64) Value {
- if v == nil {
- return NullValue(TypeInterval)
- }
- return OptionalValue(IntervalValue(*v))
+ return value.NullableIntervalValueFromMicroseconds(v)
}
func NullableIntervalValueFromMicroseconds(v *int64) Value {
- if v == nil {
- return NullValue(TypeInterval)
- }
- return OptionalValue(IntervalValueFromMicroseconds(*v))
+ return value.NullableIntervalValueFromMicroseconds(v)
}
func NullableIntervalValueFromDuration(v *time.Duration) Value {
- if v == nil {
- return NullValue(TypeInterval)
- }
- return OptionalValue(IntervalValueFromDuration(*v))
+ return value.NullableIntervalValueFromDuration(v)
}
// NullableStringValue
//
// Deprecated: use NullableBytesValue instead
func NullableStringValue(v *[]byte) Value {
- if v == nil {
- return NullValue(TypeBytes)
- }
- return OptionalValue(StringValue(*v))
+ return value.NullableBytesValue(v)
}
func NullableBytesValue(v *[]byte) Value {
- if v == nil {
- return NullValue(TypeBytes)
- }
- return OptionalValue(BytesValue(*v))
+ return value.NullableBytesValue(v)
}
func NullableStringValueFromString(v *string) Value {
- if v == nil {
- return NullValue(TypeBytes)
- }
- return OptionalValue(BytesValueFromString(*v))
+ return value.NullableBytesValueFromString(v)
}
func NullableBytesValueFromString(v *string) Value {
- if v == nil {
- return NullValue(TypeBytes)
- }
- return OptionalValue(BytesValueFromString(*v))
+ return value.NullableBytesValueFromString(v)
}
func NullableUTF8Value(v *string) Value {
- if v == nil {
- return NullValue(TypeText)
- }
- return OptionalValue(TextValue(*v))
+ return value.NullableTextValue(v)
}
func NullableTextValue(v *string) Value {
- if v == nil {
- return NullValue(TypeText)
- }
- return OptionalValue(TextValue(*v))
+ return value.NullableTextValue(v)
}
func NullableYSONValue(v *string) Value {
- if v == nil {
- return NullValue(TypeYSON)
- }
- return OptionalValue(YSONValue(*v))
+ return value.NullableYSONValue(v)
}
func NullableYSONValueFromBytes(v *[]byte) Value {
- if v == nil {
- return NullValue(TypeYSON)
- }
- return OptionalValue(YSONValueFromBytes(*v))
+ return value.NullableYSONValueFromBytes(v)
}
func NullableJSONValue(v *string) Value {
- if v == nil {
- return NullValue(TypeJSON)
- }
- return OptionalValue(JSONValue(*v))
+ return value.NullableJSONValue(v)
}
func NullableJSONValueFromBytes(v *[]byte) Value {
- if v == nil {
- return NullValue(TypeJSON)
- }
- return OptionalValue(JSONValueFromBytes(*v))
+ return value.NullableJSONValueFromBytes(v)
}
func NullableUUIDValue(v *[16]byte) Value {
- if v == nil {
- return NullValue(TypeUUID)
- }
- return OptionalValue(UUIDValue(*v))
+ return value.NullableUUIDValue(v)
}
func NullableJSONDocumentValue(v *string) Value {
- if v == nil {
- return NullValue(TypeJSONDocument)
- }
- return OptionalValue(JSONDocumentValue(*v))
+ return value.NullableJSONDocumentValue(v)
}
func NullableJSONDocumentValueFromBytes(v *[]byte) Value {
- if v == nil {
- return NullValue(TypeJSONDocument)
- }
- return OptionalValue(JSONDocumentValueFromBytes(*v))
+ return value.NullableJSONDocumentValueFromBytes(v)
}
func NullableDyNumberValue(v *string) Value {
- if v == nil {
- return NullValue(TypeDyNumber)
- }
- return OptionalValue(DyNumberValue(*v))
+ return value.NullableDyNumberValue(v)
}
-// Nullable makes optional value from nullable type
-// Warning: type interface will be replaced in the future with typed parameters pattern from go1.18
-//
-//nolint:gocyclo
func Nullable(t Type, v interface{}) Value {
- switch t {
- case TypeBool:
- return NullableBoolValue(v.(*bool))
- case TypeInt8:
- return NullableInt8Value(v.(*int8))
- case TypeUint8:
- return NullableUint8Value(v.(*uint8))
- case TypeInt16:
- return NullableInt16Value(v.(*int16))
- case TypeUint16:
- return NullableUint16Value(v.(*uint16))
- case TypeInt32:
- return NullableInt32Value(v.(*int32))
- case TypeUint32:
- return NullableUint32Value(v.(*uint32))
- case TypeInt64:
- return NullableInt64Value(v.(*int64))
- case TypeUint64:
- return NullableUint64Value(v.(*uint64))
- case TypeFloat:
- return NullableFloatValue(v.(*float32))
- case TypeDouble:
- return NullableDoubleValue(v.(*float64))
- case TypeDate:
- switch tt := v.(type) {
- case *uint32:
- return NullableDateValue(tt)
- case *time.Time:
- return NullableDateValueFromTime(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeDate", tt))
- }
- case TypeDatetime:
- switch tt := v.(type) {
- case *uint32:
- return NullableDatetimeValue(tt)
- case *time.Time:
- return NullableDatetimeValueFromTime(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeDatetime", tt))
- }
- case TypeTimestamp:
- switch tt := v.(type) {
- case *uint64:
- return NullableTimestampValue(tt)
- case *time.Time:
- return NullableTimestampValueFromTime(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeTimestamp", tt))
- }
- case TypeInterval:
- switch tt := v.(type) {
- case *int64:
- return NullableIntervalValueFromMicroseconds(tt)
- case *time.Duration:
- return NullableIntervalValueFromDuration(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeInterval", tt))
- }
- case TypeTzDate:
- switch tt := v.(type) {
- case *string:
- return NullableTzDateValue(tt)
- case *time.Time:
- return NullableTzDateValueFromTime(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeTzDate", tt))
- }
- case TypeTzDatetime:
- switch tt := v.(type) {
- case *string:
- return NullableTzDatetimeValue(tt)
- case *time.Time:
- return NullableTzDatetimeValueFromTime(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeTzDatetime", tt))
- }
- case TypeTzTimestamp:
- switch tt := v.(type) {
- case *string:
- return NullableTzTimestampValue(tt)
- case *time.Time:
- return NullableTzTimestampValueFromTime(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeTzTimestamp", tt))
- }
- case TypeBytes:
- switch tt := v.(type) {
- case *[]byte:
- return NullableBytesValue(tt)
- case *string:
- return NullableStringValueFromString(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeBytes", tt))
- }
- case TypeText:
- switch tt := v.(type) {
- case *string:
- return NullableTextValue(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeText", tt))
- }
- case TypeYSON:
- switch tt := v.(type) {
- case *string:
- return NullableYSONValue(tt)
- case *[]byte:
- return NullableYSONValueFromBytes(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeYSON", tt))
- }
- case TypeJSON:
- switch tt := v.(type) {
- case *string:
- return NullableJSONValue(tt)
- case *[]byte:
- return NullableJSONValueFromBytes(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeJSON", tt))
- }
- case TypeUUID:
- switch tt := v.(type) {
- case *[16]byte:
- return NullableUUIDValue(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeUUID", tt))
- }
- case TypeJSONDocument:
- switch tt := v.(type) {
- case *string:
- return NullableJSONDocumentValue(tt)
- case *[]byte:
- return NullableJSONDocumentValueFromBytes(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeJSONDocument", tt))
- }
- case TypeDyNumber:
- switch tt := v.(type) {
- case *string:
- return NullableDyNumberValue(tt)
- default:
- panic(fmt.Sprintf("unsupported type conversion from %T to TypeDyNumber", tt))
- }
- default:
- panic(fmt.Sprintf("unsupported type: %T", t))
- }
+ return value.Nullable(t, v)
}
diff --git a/table/types/value_test.go b/table/types/value_test.go
deleted file mode 100644
index 598272c09..000000000
--- a/table/types/value_test.go
+++ /dev/null
@@ -1,617 +0,0 @@
-package types
-
-import (
- "fmt"
- "reflect"
- "testing"
- "time"
-
- "github.com/stretchr/testify/require"
- "google.golang.org/protobuf/proto"
-
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
-)
-
-func TestNullable(t *testing.T) {
- for _, test := range []struct {
- name string
- t Type
- v interface{}
- exp Value
- }{
- {
- name: "bool",
- t: TypeBool,
- v: func(v bool) *bool { return &v }(true),
- exp: OptionalValue(BoolValue(true)),
- },
- {
- name: "nil bool",
- t: TypeBool,
- v: func() *bool { return nil }(),
- exp: NullValue(TypeBool),
- },
- {
- name: "int8",
- t: TypeInt8,
- v: func(v int8) *int8 { return &v }(123),
- exp: OptionalValue(Int8Value(123)),
- },
- {
- name: "nil int8",
- t: TypeInt8,
- v: func() *int8 { return nil }(),
- exp: NullValue(TypeInt8),
- },
- {
- name: "uint8",
- t: TypeUint8,
- v: func(v uint8) *uint8 { return &v }(123),
- exp: OptionalValue(Uint8Value(123)),
- },
- {
- name: "nil uint8",
- t: TypeUint8,
- v: func() *uint8 { return nil }(),
- exp: NullValue(TypeUint8),
- },
- {
- name: "int16",
- t: TypeInt16,
- v: func(v int16) *int16 { return &v }(123),
- exp: OptionalValue(Int16Value(123)),
- },
- {
- name: "nil int16",
- t: TypeInt16,
- v: func() *int16 { return nil }(),
- exp: NullValue(TypeInt16),
- },
- {
- name: "uint16",
- t: TypeUint16,
- v: func(v uint16) *uint16 { return &v }(123),
- exp: OptionalValue(Uint16Value(123)),
- },
- {
- name: "nil uint16",
- t: TypeUint16,
- v: func() *uint16 { return nil }(),
- exp: NullValue(TypeUint16),
- },
- {
- name: "int32",
- t: TypeInt32,
- v: func(v int32) *int32 { return &v }(123),
- exp: OptionalValue(Int32Value(123)),
- },
- {
- name: "nil int32",
- t: TypeInt32,
- v: func() *int32 { return nil }(),
- exp: NullValue(TypeInt32),
- },
- {
- name: "uint32",
- t: TypeUint32,
- v: func(v uint32) *uint32 { return &v }(123),
- exp: OptionalValue(Uint32Value(123)),
- },
- {
- name: "nil uint32",
- t: TypeUint32,
- v: func() *uint32 { return nil }(),
- exp: NullValue(TypeUint32),
- },
- {
- name: "int64",
- t: TypeInt64,
- v: func(v int64) *int64 { return &v }(123),
- exp: OptionalValue(Int64Value(123)),
- },
- {
- name: "nil int64",
- t: TypeInt64,
- v: func() *int64 { return nil }(),
- exp: NullValue(TypeInt64),
- },
- {
- name: "uint64",
- t: TypeUint64,
- v: func(v uint64) *uint64 { return &v }(123),
- exp: OptionalValue(Uint64Value(123)),
- },
- {
- name: "nil uint64",
- t: TypeUint64,
- v: func() *uint64 { return nil }(),
- exp: NullValue(TypeUint64),
- },
- {
- name: "float",
- t: TypeFloat,
- v: func(v float32) *float32 { return &v }(123),
- exp: OptionalValue(FloatValue(123)),
- },
- {
- name: "nil float",
- t: TypeFloat,
- v: func() *float32 { return nil }(),
- exp: NullValue(TypeFloat),
- },
- {
- name: "double",
- t: TypeDouble,
- v: func(v float64) *float64 { return &v }(123),
- exp: OptionalValue(DoubleValue(123)),
- },
- {
- name: "nil float",
- t: TypeDouble,
- v: func() *float64 { return nil }(),
- exp: NullValue(TypeDouble),
- },
- {
- name: "date from int32",
- t: TypeDate,
- v: func(v uint32) *uint32 { return &v }(123),
- exp: OptionalValue(DateValue(123)),
- },
- {
- name: "date from time.Time",
- t: TypeDate,
- v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
- exp: OptionalValue(DateValueFromTime(time.Unix(123, 456))),
- },
- {
- name: "nil date",
- t: TypeDate,
- v: func() *uint32 { return nil }(),
- exp: NullValue(TypeDate),
- },
- {
- name: "datetime from int32",
- t: TypeDatetime,
- v: func(v uint32) *uint32 { return &v }(123),
- exp: OptionalValue(DatetimeValue(123)),
- },
- {
- name: "datetime from time.Time",
- t: TypeDatetime,
- v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
- exp: OptionalValue(DatetimeValueFromTime(time.Unix(123, 456))),
- },
- {
- name: "nil datetime",
- t: TypeDatetime,
- v: func() *uint32 { return nil }(),
- exp: NullValue(TypeDatetime),
- },
- {
- name: "timestamp from int32",
- t: TypeTimestamp,
- v: func(v uint64) *uint64 { return &v }(123),
- exp: OptionalValue(TimestampValue(123)),
- },
- {
- name: "timestamp from time.Time",
- t: TypeTimestamp,
- v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
- exp: OptionalValue(TimestampValueFromTime(time.Unix(123, 456))),
- },
- {
- name: "nil timestamp",
- t: TypeTimestamp,
- v: func() *uint64 { return nil }(),
- exp: NullValue(TypeTimestamp),
- },
- {
- name: "tzDate from int32",
- t: TypeTzDate,
- v: func(v string) *string { return &v }(""),
- exp: OptionalValue(TzDateValue("")),
- },
- {
- name: "tzDate from time.Time",
- t: TypeTzDate,
- v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
- exp: OptionalValue(TzDateValueFromTime(time.Unix(123, 456))),
- },
- {
- name: "nil tzDate",
- t: TypeTzDate,
- v: func() *string { return nil }(),
- exp: NullValue(TypeTzDate),
- },
- {
- name: "interval from int64",
- t: TypeInterval,
- v: func(v int64) *int64 { return &v }(123),
- exp: OptionalValue(IntervalValueFromMicroseconds(123)),
- },
- {
- name: "interval from time.Time",
- t: TypeInterval,
- v: func(v time.Duration) *time.Duration { return &v }(time.Second),
- exp: OptionalValue(IntervalValueFromDuration(time.Second)),
- },
- {
- name: "nil interval",
- t: TypeInterval,
- v: func() *int64 { return nil }(),
- exp: NullValue(TypeInterval),
- },
- {
- name: "tzDatetime from int32",
- t: TypeTzDatetime,
- v: func(v string) *string { return &v }(""),
- exp: OptionalValue(TzDatetimeValue("")),
- },
- {
- name: "tzTzDatetime from time.Time",
- t: TypeTzDatetime,
- v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
- exp: OptionalValue(TzDatetimeValueFromTime(time.Unix(123, 456))),
- },
- {
- name: "nil tzTzDatetime",
- t: TypeTzDatetime,
- v: func() *string { return nil }(),
- exp: NullValue(TypeTzDatetime),
- },
- {
- name: "tzTimestamp from int32",
- t: TypeTzTimestamp,
- v: func(v string) *string { return &v }(""),
- exp: OptionalValue(TzTimestampValue("")),
- },
- {
- name: "TzTimestamp from time.Time",
- t: TypeTzTimestamp,
- v: func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
- exp: OptionalValue(TzTimestampValueFromTime(time.Unix(123, 456))),
- },
- {
- name: "nil TzTimestamp",
- t: TypeTzTimestamp,
- v: func() *string { return nil }(),
- exp: NullValue(TypeTzTimestamp),
- },
- {
- name: "string",
- t: TypeBytes,
- v: func(v string) *string { return &v }("test"),
- exp: OptionalValue(BytesValueFromString("test")),
- },
- {
- name: "string",
- t: TypeBytes,
- v: func(v []byte) *[]byte { return &v }([]byte("test")),
- exp: OptionalValue(BytesValueFromString("test")),
- },
- {
- name: "nil string",
- t: TypeBytes,
- v: func() *string { return nil }(),
- exp: NullValue(TypeBytes),
- },
- {
- name: "utf8",
- t: TypeText,
- v: func(v string) *string { return &v }("test"),
- exp: OptionalValue(TextValue("test")),
- },
- {
- name: "nil utf8",
- t: TypeText,
- v: func() *string { return nil }(),
- exp: NullValue(TypeText),
- },
- {
- name: "yson",
- t: TypeYSON,
- v: func(v string) *string { return &v }("test"),
- exp: OptionalValue(YSONValue("test")),
- },
- {
- name: "yson",
- t: TypeYSON,
- v: func(v []byte) *[]byte { return &v }([]byte("test")),
- exp: OptionalValue(YSONValueFromBytes([]byte("test"))),
- },
- {
- name: "nil yson",
- t: TypeYSON,
- v: func() *string { return nil }(),
- exp: NullValue(TypeYSON),
- },
- {
- name: "json",
- t: TypeJSON,
- v: func(v string) *string { return &v }("test"),
- exp: OptionalValue(JSONValue("test")),
- },
- {
- name: "json",
- t: TypeJSON,
- v: func(v []byte) *[]byte { return &v }([]byte("test")),
- exp: OptionalValue(JSONValueFromBytes([]byte("test"))),
- },
- {
- name: "nil json",
- t: TypeJSON,
- v: func() *string { return nil }(),
- exp: NullValue(TypeJSON),
- },
- {
- name: "uuid",
- t: TypeUUID,
- v: func(v [16]byte) *[16]byte { return &v }([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}),
- exp: OptionalValue(UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})),
- },
- {
- name: "jsonDocument",
- t: TypeJSONDocument,
- v: func(v string) *string { return &v }("test"),
- exp: OptionalValue(JSONDocumentValue("test")),
- },
- {
- name: "jsonDocument",
- t: TypeJSONDocument,
- v: func(v []byte) *[]byte { return &v }([]byte("test")),
- exp: OptionalValue(JSONDocumentValueFromBytes([]byte("test"))),
- },
- {
- name: "nil jsonDocument",
- t: TypeJSONDocument,
- v: func() *string { return nil }(),
- exp: NullValue(TypeJSONDocument),
- },
- {
- name: "dyNumber",
- t: TypeDyNumber,
- v: func(v string) *string { return &v }("test"),
- exp: OptionalValue(DyNumberValue("test")),
- },
- {
- name: "nil dyNumber",
- t: TypeDyNumber,
- v: func() *string { return nil }(),
- exp: NullValue(TypeDyNumber),
- },
- } {
- t.Run(test.name, func(t *testing.T) {
- a := allocator.New()
- defer a.Free()
- v := Nullable(test.t, test.v)
- if !proto.Equal(value.ToYDB(v, a), value.ToYDB(test.exp, a)) {
- t.Fatalf("unexpected value: %v, exp: %v", v, test.exp)
- }
- })
- }
-}
-
-func TestCastNumbers(t *testing.T) {
- numberValues := []struct {
- value Value
- signed bool
- len int
- }{
- {
- value: Uint64Value(1),
- signed: false,
- len: 8,
- },
- {
- value: Int64Value(2),
- signed: true,
- len: 8,
- },
- {
- value: Uint32Value(3),
- signed: false,
- len: 4,
- },
- {
- value: Int32Value(4),
- signed: true,
- len: 4,
- },
- {
- value: Uint16Value(5),
- signed: false,
- len: 2,
- },
- {
- value: Int16Value(6),
- signed: true,
- len: 2,
- },
- {
- value: Uint8Value(7),
- signed: false,
- len: 1,
- },
- {
- value: Int8Value(8),
- signed: true,
- len: 1,
- },
- }
- numberDestinations := []struct {
- destination interface{}
- signed bool
- len int
- }{
- {
- destination: func(v uint64) *uint64 { return &v }(1),
- signed: false,
- len: 8,
- },
- {
- destination: func(v int64) *int64 { return &v }(2),
- signed: true,
- len: 8,
- },
- {
- destination: func(v uint32) *uint32 { return &v }(3),
- signed: false,
- len: 4,
- },
- {
- destination: func(v int32) *int32 { return &v }(4),
- signed: true,
- len: 4,
- },
- {
- destination: func(v uint16) *uint16 { return &v }(5),
- signed: false,
- len: 2,
- },
- {
- destination: func(v int16) *int16 { return &v }(6),
- signed: true,
- len: 2,
- },
- {
- destination: func(v uint8) *uint8 { return &v }(7),
- signed: false,
- len: 1,
- },
- {
- destination: func(v int8) *int8 { return &v }(8),
- signed: true,
- len: 1,
- },
- {
- destination: func(v float32) *float32 { return &v }(7),
- signed: true,
- len: 4,
- },
- {
- destination: func(v float64) *float64 { return &v }(8),
- signed: true,
- len: 8,
- },
- }
- for _, dst := range numberDestinations {
- t.Run(reflect.ValueOf(dst.destination).Type().Elem().String(), func(t *testing.T) {
- for _, src := range numberValues {
- t.Run(src.value.Yql(), func(t *testing.T) {
- mustErr := false
- switch {
- case src.len == dst.len && src.signed != dst.signed,
- src.len > dst.len,
- src.signed && !dst.signed:
- mustErr = true
- }
- err := CastTo(src.value, dst.destination)
- if mustErr {
- require.Error(t, err)
- } else {
- require.NoError(t, err)
- }
- })
- t.Run(OptionalValue(src.value).Yql(), func(t *testing.T) {
- mustErr := false
- switch {
- case src.len == dst.len && src.signed != dst.signed,
- src.len > dst.len,
- src.signed && !dst.signed:
- mustErr = true
- }
- err := CastTo(OptionalValue(src.value), dst.destination)
- if mustErr {
- require.Error(t, err)
- } else {
- require.NoError(t, err)
- }
- })
- }
- })
- }
-}
-
-func TestCastOtherTypes(t *testing.T) {
- for _, tt := range []struct {
- v Value
- dst interface{}
- result interface{}
- error bool
- }{
- {
- v: BytesValue([]byte("test")),
- dst: func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)),
- result: func(v []byte) *[]byte { return &v }([]byte("test")),
- error: false,
- },
- {
- v: TextValue("test"),
- dst: func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)),
- result: func(v []byte) *[]byte { return &v }([]byte("test")),
- error: false,
- },
- {
- v: BytesValue([]byte("test")),
- dst: func(v string) *string { return &v }(""),
- result: func(v string) *string { return &v }("test"),
- error: false,
- },
- {
- v: DoubleValue(123),
- dst: func(v float64) *float64 { return &v }(9),
- result: func(v float64) *float64 { return &v }(123),
- error: false,
- },
- {
- v: DoubleValue(123),
- dst: func(v float32) *float32 { return &v }(9),
- result: func(v float32) *float32 { return &v }(9),
- error: true,
- },
- {
- v: FloatValue(123),
- dst: func(v float64) *float64 { return &v }(9),
- result: func(v float64) *float64 { return &v }(123),
- error: false,
- },
- {
- v: FloatValue(123),
- dst: func(v float32) *float32 { return &v }(9),
- result: func(v float32) *float32 { return &v }(123),
- error: false,
- },
- {
- v: Uint64Value(123),
- dst: func(v float32) *float32 { return &v }(9),
- result: func(v float32) *float32 { return &v }(9),
- error: true,
- },
- {
- v: Uint64Value(123),
- dst: func(v float64) *float64 { return &v }(9),
- result: func(v float64) *float64 { return &v }(9),
- error: true,
- },
- {
- v: OptionalValue(DoubleValue(123)),
- dst: func(v float64) *float64 { return &v }(9),
- result: func(v float64) *float64 { return &v }(123),
- error: false,
- },
- } {
- t.Run(fmt.Sprintf("cast %s to %v", tt.v.Type().Yql(), reflect.ValueOf(tt.dst).Type().Elem()),
- func(t *testing.T) {
- if err := CastTo(tt.v, tt.dst); (err != nil) != tt.error {
- t.Errorf("castTo() error = %v, want %v", err, tt.error)
- } else if !reflect.DeepEqual(tt.dst, tt.result) {
- t.Errorf("castTo() result = %+v, want %+v",
- reflect.ValueOf(tt.dst).Elem(),
- reflect.ValueOf(tt.result).Elem(),
- )
- }
- },
- )
- }
-}
diff --git a/tests/integration/basic_example_database_sql_bindings_test.go b/tests/integration/basic_example_database_sql_bindings_test.go
index 39d955808..b59df9461 100644
--- a/tests/integration/basic_example_database_sql_bindings_test.go
+++ b/tests/integration/basic_example_database_sql_bindings_test.go
@@ -10,6 +10,7 @@ import (
"fmt"
"os"
"path"
+ "sync/atomic"
"testing"
"time"
@@ -17,7 +18,6 @@ import (
"google.golang.org/grpc/metadata"
"github.com/ydb-platform/ydb-go-sdk/v3"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/meta"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
@@ -31,7 +31,7 @@ func TestBasicExampleDatabaseSqlBindings(t *testing.T) {
ctx, cancel := context.WithTimeout(xtest.Context(t), 42*time.Second)
defer cancel()
- var totalConsumedUnits xatomic.Uint64
+ var totalConsumedUnits atomic.Uint64
defer func() {
t.Logf("total consumed units: %d", totalConsumedUnits.Load())
}()
diff --git a/tests/integration/basic_example_database_sql_test.go b/tests/integration/basic_example_database_sql_test.go
index bf478ecd0..06af67bf9 100644
--- a/tests/integration/basic_example_database_sql_test.go
+++ b/tests/integration/basic_example_database_sql_test.go
@@ -10,6 +10,7 @@ import (
"fmt"
"os"
"path"
+ "sync/atomic"
"testing"
"time"
@@ -17,7 +18,6 @@ import (
"google.golang.org/grpc/metadata"
"github.com/ydb-platform/ydb-go-sdk/v3"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/meta"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
@@ -31,7 +31,7 @@ func TestBasicExampleDatabaseSql(t *testing.T) {
ctx, cancel := context.WithTimeout(xtest.Context(t), 42*time.Second)
defer cancel()
- var totalConsumedUnits xatomic.Uint64
+ var totalConsumedUnits atomic.Uint64
defer func() {
t.Logf("total consumed units: %d", totalConsumedUnits.Load())
}()
diff --git a/tests/integration/basic_example_native_test.go b/tests/integration/basic_example_native_test.go
index f7d5deb6a..1e4231e5f 100644
--- a/tests/integration/basic_example_native_test.go
+++ b/tests/integration/basic_example_native_test.go
@@ -13,6 +13,7 @@ import (
"runtime/debug"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -24,7 +25,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/balancers"
"github.com/ydb-platform/ydb-go-sdk/v3/config"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
"github.com/ydb-platform/ydb-go-sdk/v3/log"
"github.com/ydb-platform/ydb-go-sdk/v3/meta"
@@ -160,7 +160,7 @@ func TestBasicExampleNative(t *testing.T) { //nolint:gocyclo
ctx, cancel := context.WithTimeout(context.Background(), 42*time.Second)
defer cancel()
- var totalConsumedUnits xatomic.Uint64
+ var totalConsumedUnits atomic.Uint64
defer func() {
t.Logf("total consumed units: %d", totalConsumedUnits.Load())
}()
@@ -195,7 +195,7 @@ func TestBasicExampleNative(t *testing.T) { //nolint:gocyclo
sessionsMtx sync.Mutex
sessions = make(map[string]struct{}, limit)
- shutdowned xatomic.Bool
+ shutdowned atomic.Bool
shutdownTrace = trace.Table{
OnPoolSessionAdd: func(info trace.TablePoolSessionAddInfo) {
@@ -232,7 +232,7 @@ func TestBasicExampleNative(t *testing.T) { //nolint:gocyclo
db, err := ydb.Open(ctx,
os.Getenv("YDB_CONNECTION_STRING"),
ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
- ydb.WithUserAgent("table/e2e"),
+ ydb.WithApplicationName("table/e2e"),
withMetrics(t, trace.DetailsAll, time.Second),
ydb.With(
config.WithOperationTimeout(time.Second*5),
diff --git a/tests/integration/connection_test.go b/tests/integration/connection_test.go
index d4aecc63c..fcbcfb837 100644
--- a/tests/integration/connection_test.go
+++ b/tests/integration/connection_test.go
@@ -46,7 +46,7 @@ func TestConnection(t *testing.T) {
if !has {
t.Fatalf("no medatada")
}
- userAgents := md.Get(meta.HeaderUserAgent)
+ userAgents := md.Get(meta.HeaderApplicationName)
if len(userAgents) == 0 {
t.Fatalf("no user agent")
}
@@ -87,7 +87,7 @@ func TestConnection(t *testing.T) {
newLoggerWithMinLevel(t, log.WARN),
trace.MatchDetails(`ydb\.(driver|discovery|retry|scheme).*`),
),
- ydb.WithUserAgent(userAgent),
+ ydb.WithApplicationName(userAgent),
ydb.WithRequestsType(requestType),
ydb.With(
config.WithGrpcOptions(
diff --git a/tests/integration/connection_with_compression_test.go b/tests/integration/connection_with_compression_test.go
index cdb15ddac..c0be662b4 100644
--- a/tests/integration/connection_with_compression_test.go
+++ b/tests/integration/connection_with_compression_test.go
@@ -45,7 +45,7 @@ func TestConnectionWithCompression(t *testing.T) {
if !has {
t.Fatalf("no medatada")
}
- userAgents := md.Get(meta.HeaderUserAgent)
+ userAgents := md.Get(meta.HeaderApplicationName)
if len(userAgents) == 0 {
t.Fatalf("no user agent")
}
@@ -79,7 +79,7 @@ func TestConnectionWithCompression(t *testing.T) {
newLoggerWithMinLevel(t, log.WARN),
trace.MatchDetails(`ydb\.(driver|discovery|retry|scheme).*`),
),
- ydb.WithUserAgent(userAgent),
+ ydb.WithApplicationName(userAgent),
ydb.WithRequestsType(requestType),
ydb.With(
config.WithGrpcOptions(
diff --git a/tests/integration/database_sql_containers_test.go b/tests/integration/database_sql_containers_test.go
index bbb8cc2db..5e8ae71f8 100644
--- a/tests/integration/database_sql_containers_test.go
+++ b/tests/integration/database_sql_containers_test.go
@@ -149,7 +149,7 @@ func (s *testDatabaseSqlContainersExampleStruct) Scan(res interface{}) error {
return nil
}
}
- return fmt.Errorf("type '%T' is not a `types.Value` type", res)
+ return fmt.Errorf("type '%T' is not a `types.value` type", res)
}
type testDatabaseSqlContainersExampleList []string
diff --git a/tests/integration/database_sql_ignore_placeholder_test.go b/tests/integration/database_sql_ignore_placeholder_test.go
new file mode 100644
index 000000000..8bc6cac27
--- /dev/null
+++ b/tests/integration/database_sql_ignore_placeholder_test.go
@@ -0,0 +1,43 @@
+//go:build integration
+// +build integration
+
+package integration
+
+import (
+ "context"
+ "database/sql"
+ "testing"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/retry"
+)
+
+func TestDatabaseSqlDiscardColumn(t *testing.T) {
+ scope := newScope(t)
+ db := scope.SQLDriverWithFolder(
+ ydb.WithTablePathPrefix(scope.Folder()),
+ ydb.WithAutoDeclare(),
+ ydb.WithNumericArgs(),
+ )
+ dt := time.Date(2023, 3, 1, 16, 34, 18, 0, time.UTC)
+
+ var row *sql.Row
+ err := retry.Retry(scope.Ctx, func(ctx context.Context) (err error) {
+ row = db.QueryRowContext(ctx, `
+ SELECT
+ $1 AS vInt,
+ $2 AS __discard_column_1,
+ $3 AS __discard_column_2,
+ $4 AS __discard_column_3
+ `, 1, "2", 3.0, dt,
+ )
+ return row.Err()
+ })
+ scope.Require.NoError(err)
+
+ var resInt int
+ scope.Require.NoError(row.Scan(&resInt))
+
+ scope.Require.Equal(1, resInt)
+}
diff --git a/tests/integration/discovery_test.go b/tests/integration/discovery_test.go
index 410605bbf..511043ebd 100644
--- a/tests/integration/discovery_test.go
+++ b/tests/integration/discovery_test.go
@@ -31,12 +31,12 @@ func TestDiscovery(t *testing.T) {
if !has {
t.Fatalf("no medatada")
}
- userAgents := md.Get(meta.HeaderUserAgent)
- if len(userAgents) == 0 {
- t.Fatalf("no user agent")
+ applicationName := md.Get(meta.HeaderApplicationName)
+ if len(applicationName) == 0 {
+ t.Fatalf("no application name")
}
- if userAgents[0] != userAgent {
- t.Fatalf("unknown user agent: %s", userAgents[0])
+ if applicationName[0] != userAgent {
+ t.Fatalf("unknown user agent: %s", applicationName[0])
}
requestTypes := md.Get(meta.HeaderRequestType)
if len(requestTypes) == 0 {
@@ -66,7 +66,7 @@ func TestDiscovery(t *testing.T) {
newLoggerWithMinLevel(t, log.WARN),
trace.MatchDetails(`ydb\.(driver|discovery|repeater).*`),
),
- ydb.WithUserAgent(userAgent),
+ ydb.WithApplicationName(userAgent),
ydb.WithRequestsType(requestType),
ydb.With(
config.WithGrpcOptions(
diff --git a/tests/integration/helpers_test.go b/tests/integration/helpers_test.go
index 6a1a6afa4..73363250d 100644
--- a/tests/integration/helpers_test.go
+++ b/tests/integration/helpers_test.go
@@ -79,7 +79,7 @@ func (scope *scopeT) AuthToken() string {
}
func (scope *scopeT) Driver(opts ...ydb.Option) *ydb.Driver {
- return scope.CacheWithCleanup("", nil, func() (res interface{}, cleanup fixenv.FixtureCleanupFunc, err error) {
+ f := func() (*fixenv.GenericResult[*ydb.Driver], error) {
connectionString := scope.ConnectionString()
scope.Logf("Connect with connection string: %v", connectionString)
@@ -105,8 +105,11 @@ func (scope *scopeT) Driver(opts ...ydb.Option) *ydb.Driver {
clean := func() {
scope.Require.NoError(driver.Close(scope.Ctx))
}
- return driver, clean, err
- }).(*ydb.Driver)
+
+ return fixenv.NewGenericResultWithCleanup(driver, clean), err
+ }
+
+ return fixenv.CacheResult(scope.Env, f)
}
func (scope *scopeT) SQLDriver(opts ...ydb.ConnectorOption) *sql.DB {
@@ -136,7 +139,7 @@ func (scope *scopeT) SQLDriverWithFolder(opts ...ydb.ConnectorOption) *sql.DB {
}
func (scope *scopeT) Folder() string {
- return scope.CacheWithCleanup(nil, nil, func() (res interface{}, cleanup fixenv.FixtureCleanupFunc, err error) {
+ f := func() (*fixenv.GenericResult[string], error) {
driver := scope.Driver()
folderPath := path.Join(driver.Name(), scope.T().Name())
scope.Require.NoError(sugar.RemoveRecursive(scope.Ctx, driver, folderPath))
@@ -148,8 +151,9 @@ func (scope *scopeT) Folder() string {
scope.Require.NoError(sugar.RemoveRecursive(scope.Ctx, driver, folderPath))
}
}
- return folderPath, clean, nil
- }).(string)
+ return fixenv.NewGenericResultWithCleanup(folderPath, clean), nil
+ }
+ return fixenv.CacheResult(scope.Env, f)
}
func (scope *scopeT) Logger() *testLogger {
@@ -169,57 +173,62 @@ func (scope *scopeT) TopicConsumerName() string {
}
func (scope *scopeT) TopicPath() string {
- return scope.CacheWithCleanup(nil, nil, func() (res interface{}, cleanup fixenv.FixtureCleanupFunc, err error) {
+ f := func() (*fixenv.GenericResult[string], error) {
topicName := strings.Replace(scope.T().Name(), "/", "__", -1)
topicPath := path.Join(scope.Folder(), topicName)
client := scope.Driver().Topic()
- cleanup = func() {
+ cleanup := func() {
if !scope.Failed() {
_ = client.Drop(scope.Ctx, topicPath)
}
}
cleanup()
- err = client.Create(scope.Ctx, topicPath, topicoptions.CreateWithConsumer(
+ err := client.Create(scope.Ctx, topicPath, topicoptions.CreateWithConsumer(
topictypes.Consumer{
Name: scope.TopicConsumerName(),
},
))
- return topicPath, cleanup, err
- }).(string)
+ return fixenv.NewGenericResultWithCleanup(topicPath, cleanup), err
+ }
+ return fixenv.CacheResult(scope.Env, f)
}
func (scope *scopeT) TopicReader() *topicreader.Reader {
- return scope.CacheWithCleanup(nil, nil, func() (res interface{}, cleanup fixenv.FixtureCleanupFunc, err error) {
+ f := func() (*fixenv.GenericResult[*topicreader.Reader], error) {
reader, err := scope.Driver().Topic().StartReader(
scope.TopicConsumerName(),
topicoptions.ReadTopic(scope.TopicPath()),
)
- cleanup = func() {
+ cleanup := func() {
if reader != nil {
_ = reader.Close(scope.Ctx)
}
}
- return reader, cleanup, err
- }).(*topicreader.Reader)
+ return fixenv.NewGenericResultWithCleanup(reader, cleanup), err
+ }
+
+ return fixenv.CacheResult(scope.Env, f)
}
func (scope *scopeT) TopicWriter() *topicwriter.Writer {
- return scope.CacheWithCleanup(nil, nil, func() (res interface{}, cleanup fixenv.FixtureCleanupFunc, err error) {
+ f := func() (*fixenv.GenericResult[*topicwriter.Writer], error) {
writer, err := scope.Driver().Topic().StartWriter(
scope.TopicPath(),
topicoptions.WithWriterProducerID(scope.TopicWriterProducerID()),
topicoptions.WithWriterWaitServerAck(true),
)
- cleanup = func() {
+ cleanup := func() {
if writer != nil {
_ = writer.Close(scope.Ctx)
}
}
- return writer, cleanup, err
- }).(*topicwriter.Writer)
+ return fixenv.NewGenericResultWithCleanup(writer, cleanup), err
+ }
+
+ return fixenv.CacheResult(scope.Env, f)
}
func (scope *scopeT) TopicWriterProducerID() string {
@@ -266,7 +275,9 @@ func (scope *scopeT) TableName(opts ...func(t *tableNameParams)) string {
`,
}
for _, opt := range opts {
- opt(¶ms)
+ if opt != nil {
+ opt(¶ms)
+ }
}
return scope.Cache(params.tableName, nil, func() (res interface{}, err error) {
err = scope.Driver().Table().Do(scope.Ctx, func(ctx context.Context, s table.Session) (err error) {
diff --git a/tests/integration/query_execute_test.go b/tests/integration/query_execute_test.go
new file mode 100644
index 000000000..81687bae8
--- /dev/null
+++ b/tests/integration/query_execute_test.go
@@ -0,0 +1,276 @@
+//go:build integration
+// +build integration
+
+package integration
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/log"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+func TestQueryExecute(t *testing.T) {
+ if version.Lt(os.Getenv("YDB_VERSION"), "24.1") {
+ t.Skip("query service not allowed in YDB version '" + os.Getenv("YDB_VERSION") + "'")
+ }
+
+ ctx, cancel := context.WithCancel(xtest.Context(t))
+ defer cancel()
+
+ db, err := ydb.Open(ctx,
+ os.Getenv("YDB_CONNECTION_STRING"),
+ ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
+ ydb.WithSessionPoolSizeLimit(10),
+ ydb.WithTraceQuery(
+ log.Query(
+ log.Default(os.Stdout,
+ log.WithLogQuery(),
+ log.WithColoring(),
+ log.WithMinLevel(log.INFO),
+ ),
+ trace.QueryEvents,
+ ),
+ ),
+ )
+ require.NoError(t, err)
+ t.Run("Stats", func(t *testing.T) {
+ s, err := query.Stats(db.Query())
+ require.NoError(t, err)
+ require.EqualValues(t, 10, s.Limit)
+ })
+ t.Run("Scan", func(t *testing.T) {
+ var (
+ p1 string
+ p2 uint64
+ p3 time.Duration
+ )
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ _, res, err := s.Execute(ctx, `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT $p1, $p2, $p3;
+ `,
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$p1").Text("test").
+ Param("$p2").Uint64(100500000000).
+ Param("$p3").Interval(time.Duration(100500000000)).
+ Build(),
+ ),
+ query.WithSyntax(query.SyntaxYQL),
+ )
+ if err != nil {
+ return err
+ }
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ err = row.Scan(&p1, &p2, &p3)
+ if err != nil {
+ return err
+ }
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ require.EqualValues(t, "test", p1)
+ require.EqualValues(t, 100500000000, p2)
+ require.EqualValues(t, time.Duration(100500000000), p3)
+ })
+ t.Run("ScanNamed", func(t *testing.T) {
+ var (
+ p1 string
+ p2 uint64
+ p3 time.Duration
+ )
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ _, res, err := s.Execute(ctx, `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT $p1 AS p1, $p2 AS p2, $p3 AS p3;
+ `,
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$p1").Text("test").
+ Param("$p2").Uint64(100500000000).
+ Param("$p3").Interval(time.Duration(100500000000)).
+ Build(),
+ ),
+ query.WithSyntax(query.SyntaxYQL),
+ )
+ if err != nil {
+ return err
+ }
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ err = row.ScanNamed(
+ query.Named("p1", &p1),
+ query.Named("p2", &p2),
+ query.Named("p3", &p3),
+ )
+ if err != nil {
+ return err
+ }
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ require.EqualValues(t, "test", p1)
+ require.EqualValues(t, 100500000000, p2)
+ require.EqualValues(t, time.Duration(100500000000), p3)
+ })
+ t.Run("ScanStruct", func(t *testing.T) {
+ var data struct {
+ P1 *string `sql:"p1"`
+ P2 uint64 `sql:"p2"`
+ P3 time.Duration `sql:"p3"`
+ P4 *string `sql:"p4"`
+ }
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ _, res, err := s.Execute(ctx, `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT CAST($p1 AS Optional) AS p1, $p2 AS p2, $p3 AS p3, CAST(NULL AS Optional) AS p4;
+ `,
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$p1").Text("test").
+ Param("$p2").Uint64(100500000000).
+ Param("$p3").Interval(time.Duration(100500000000)).
+ Build(),
+ ),
+ query.WithSyntax(query.SyntaxYQL),
+ )
+ if err != nil {
+ return err
+ }
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ err = row.ScanStruct(&data)
+ if err != nil {
+ return err
+ }
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ require.NotNil(t, data.P1)
+ require.EqualValues(t, "test", *data.P1)
+ require.EqualValues(t, 100500000000, data.P2)
+ require.EqualValues(t, time.Duration(100500000000), data.P3)
+ require.Nil(t, data.P4)
+ })
+ t.Run("Tx", func(t *testing.T) {
+ t.Run("Explicit", func(t *testing.T) {
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ tx, err := s.Begin(ctx, query.TxSettings(query.WithSerializableReadWrite()))
+ if err != nil {
+ return err
+ }
+ res, err := tx.Execute(ctx, `SELECT 1`)
+ if err != nil {
+ return err
+ }
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ var v int32
+ err = row.Scan(&v)
+ if err != nil {
+ return err
+ }
+ if v != 1 {
+ return fmt.Errorf("unexpected value from database: %d", v)
+ }
+ if err = res.Err(); err != nil {
+ return err
+ }
+ return tx.CommitTx(ctx)
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ })
+ t.Run("Lazy", func(t *testing.T) {
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ tx, res, err := s.Execute(ctx, `SELECT 1`,
+ query.WithTxControl(query.TxControl(query.BeginTx(query.WithSerializableReadWrite()))),
+ )
+ if err != nil {
+ return err
+ }
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ var v int32
+ err = row.Scan(&v)
+ if err != nil {
+ return err
+ }
+ if v != 1 {
+ return fmt.Errorf("unexpected value from database: %d", v)
+ }
+ if err = res.Err(); err != nil {
+ return err
+ }
+ res, err = tx.Execute(ctx, `SELECT 2`, query.WithCommit())
+ if err != nil {
+ return err
+ }
+ rs, err = res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err = rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ err = row.Scan(&v)
+ if err != nil {
+ return err
+ }
+ if v != 2 {
+ return fmt.Errorf("unexpected value from database: %d", v)
+ }
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ })
+ })
+}
diff --git a/tests/integration/query_tx_execute_test.go b/tests/integration/query_tx_execute_test.go
new file mode 100644
index 000000000..91a70029a
--- /dev/null
+++ b/tests/integration/query_tx_execute_test.go
@@ -0,0 +1,64 @@
+//go:build integration
+// +build integration
+
+package integration
+
+import (
+ "context"
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
+ "github.com/ydb-platform/ydb-go-sdk/v3/log"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+func TestQueryTxExecute(t *testing.T) {
+ if version.Lt(os.Getenv("YDB_VERSION"), "24.1") {
+ t.Skip("query service not allowed in YDB version '" + os.Getenv("YDB_VERSION") + "'")
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ db, err := ydb.Open(ctx,
+ os.Getenv("YDB_CONNECTION_STRING"),
+ ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
+ ydb.WithTraceQuery(
+ log.Query(
+ log.Default(os.Stdout,
+ log.WithLogQuery(),
+ log.WithColoring(),
+ log.WithMinLevel(log.INFO),
+ ),
+ trace.QueryEvents,
+ ),
+ ),
+ )
+ require.NoError(t, err)
+ err = db.Query().DoTx(ctx, func(ctx context.Context, tx query.TxActor) (err error) {
+ res, err := tx.Execute(ctx, "SELECT 1 AS col1")
+ if err != nil {
+ return err
+ }
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ return err
+ }
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ return err
+ }
+ var col1 int
+ err = row.ScanNamed(query.Named("col1", &col1))
+ if err != nil {
+ return err
+ }
+ return res.Err()
+ }, query.WithIdempotent(), query.WithTxSettings(query.TxSettings(query.WithSerializableReadWrite())))
+ require.NoError(t, err)
+}
diff --git a/tests/integration/scripting_test.go b/tests/integration/scripting_test.go
index fb3cc9d49..b1c908e0d 100644
--- a/tests/integration/scripting_test.go
+++ b/tests/integration/scripting_test.go
@@ -40,7 +40,7 @@ func TestScripting(t *testing.T) {
newLogger(t),
trace.MatchDetails(`ydb\.(driver|discovery|retry|scheme).*`),
),
- ydb.WithUserAgent("scripting"),
+ ydb.WithApplicationName("scripting"),
)
if err != nil {
t.Fatal(err)
diff --git a/tests/integration/sugar_result_test.go b/tests/integration/sugar_result_test.go
new file mode 100644
index 000000000..ba863dd72
--- /dev/null
+++ b/tests/integration/sugar_result_test.go
@@ -0,0 +1,248 @@
+//go:build integration
+// +build integration
+
+package integration
+
+import (
+ "context"
+ "os"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/sugar"
+ "github.com/ydb-platform/ydb-go-sdk/v3/table"
+ "github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
+ "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
+)
+
+func TestSugarResult(t *testing.T) {
+ if version.Lt(os.Getenv("YDB_VERSION"), "24.1") {
+ t.Skip("query service not allowed in YDB version '" + os.Getenv("YDB_VERSION") + "'")
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ db, err := ydb.Open(ctx,
+ os.Getenv("YDB_CONNECTION_STRING"),
+ ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
+ )
+ require.NoError(t, err)
+ t.Run("Scan", func(t *testing.T) {
+ t.Run("Table", func(t *testing.T) {
+ var (
+ p1 string
+ p2 uint64
+ p3 time.Duration
+ )
+ err = db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
+ _, res, err := s.Execute(ctx, table.DefaultTxControl(), `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT $p1, $p2, $p3;
+ `,
+ table.NewQueryParameters(
+ table.ValueParam("$p1", types.TextValue("test")),
+ table.ValueParam("$p2", types.Uint64Value(100500000000)),
+ table.ValueParam("$p3", types.IntervalValueFromDuration(time.Duration(100500000000))),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ if err = res.Scan(&p1, &p2, &p3); err != nil {
+ return err
+ }
+ }
+ }
+
+ return res.Err()
+ }, table.WithIdempotent())
+ require.NoError(t, err)
+ require.EqualValues(t, "test", p1)
+ require.EqualValues(t, 100500000000, p2)
+ require.EqualValues(t, time.Duration(100500000000), p3)
+ })
+ t.Run("Sugar", func(t *testing.T) {
+ var (
+ p1 string
+ p2 uint64
+ p3 time.Duration
+ )
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ _, r, err := s.Execute(ctx, `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT $p1, $p2, $p3;
+ `,
+ query.WithParameters(
+ table.NewQueryParameters(
+ table.ValueParam("$p1", types.TextValue("test")),
+ table.ValueParam("$p2", types.Uint64Value(100500000000)),
+ table.ValueParam("$p3", types.IntervalValueFromDuration(time.Duration(100500000000))),
+ ),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+ res := sugar.Result(r)
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ if err = res.Scan(&p1, &p2, &p3); err != nil {
+ return err
+ }
+ }
+ }
+
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ require.EqualValues(t, "test", p1)
+ require.EqualValues(t, 100500000000, p2)
+ require.EqualValues(t, time.Duration(100500000000), p3)
+ })
+ })
+ t.Run("ScanNamed", func(t *testing.T) {
+ t.Run("Table", func(t *testing.T) {
+ var (
+ p1 string
+ p2 uint64
+ p3 time.Duration
+ )
+ err = db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
+ _, res, err := s.Execute(ctx, table.DefaultTxControl(), `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT $p1 AS p1, $p2 AS p2, $p3 AS p3;
+ `,
+ table.NewQueryParameters(
+ table.ValueParam("$p1", types.TextValue("test")),
+ table.ValueParam("$p2", types.Uint64Value(100500000000)),
+ table.ValueParam("$p3", types.IntervalValueFromDuration(time.Duration(100500000000))),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ if err = res.ScanNamed(
+ named.Required("p1", &p1),
+ named.Required("p2", &p2),
+ named.Required("p3", &p3),
+ ); err != nil {
+ return err
+ }
+ }
+ }
+
+ return res.Err()
+ }, table.WithIdempotent())
+ require.NoError(t, err)
+ require.EqualValues(t, "test", p1)
+ require.EqualValues(t, 100500000000, p2)
+ require.EqualValues(t, time.Duration(100500000000), p3)
+ })
+ t.Run("Sugar", func(t *testing.T) {
+ var (
+ p1 string
+ p2 uint64
+ p3 time.Duration
+ )
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ _, r, err := s.Execute(ctx, `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT $p1 AS p1, $p2 AS p2, $p3 AS p3;
+ `,
+ query.WithParameters(
+ table.NewQueryParameters(
+ table.ValueParam("$p1", types.TextValue("test")),
+ table.ValueParam("$p2", types.Uint64Value(100500000000)),
+ table.ValueParam("$p3", types.IntervalValueFromDuration(time.Duration(100500000000))),
+ ),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+ res := sugar.Result(r)
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ if err = res.ScanNamed(
+ named.Required("p1", &p1),
+ named.Required("p2", &p2),
+ named.Required("p3", &p3),
+ ); err != nil {
+ return err
+ }
+ }
+ }
+
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ require.EqualValues(t, "test", p1)
+ require.EqualValues(t, 100500000000, p2)
+ require.EqualValues(t, time.Duration(100500000000), p3)
+ })
+ })
+ t.Run("ScanStruct", func(t *testing.T) {
+ t.Run("Sugar", func(t *testing.T) {
+ var data struct {
+ P1 *string `sql:"p1"`
+ P2 uint64 `sql:"p2"`
+ P3 time.Duration `sql:"p3"`
+ P4 *string `sql:"p4"`
+ }
+ err = db.Query().Do(ctx, func(ctx context.Context, s query.Session) (err error) {
+ _, r, err := s.Execute(ctx, `
+ DECLARE $p1 AS Text;
+ DECLARE $p2 AS Uint64;
+ DECLARE $p3 AS Interval;
+ SELECT CAST($p1 AS Optional) AS p1, $p2 AS p2, $p3 AS p3, CAST(NULL AS Optional) AS p4;
+ `,
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$p1").Text("test").
+ Param("$p2").Uint64(100500000000).
+ Param("$p3").Interval(time.Duration(100500000000)).
+ Build(),
+ ),
+ query.WithSyntax(query.SyntaxYQL),
+ )
+ if err != nil {
+ return err
+ }
+ res := sugar.Result(r)
+ for res.NextResultSet(ctx) {
+ for res.NextRow() {
+ if err = res.ScanStruct(&data); err != nil {
+ return err
+ }
+ }
+ }
+
+ return res.Err()
+ }, query.WithIdempotent())
+ require.NoError(t, err)
+ require.NotNil(t, data.P1)
+ require.EqualValues(t, "test", *data.P1)
+ require.EqualValues(t, 100500000000, data.P2)
+ require.EqualValues(t, time.Duration(100500000000), data.P3)
+ require.Nil(t, data.P4)
+ })
+ })
+}
diff --git a/tests/integration/topic_partitions_balanced_test.go b/tests/integration/topic_partitions_balanced_test.go
index c0a512a4d..5ad88e15f 100644
--- a/tests/integration/topic_partitions_balanced_test.go
+++ b/tests/integration/topic_partitions_balanced_test.go
@@ -6,6 +6,7 @@ package integration
import (
"context"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -13,7 +14,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topictypes"
@@ -38,8 +38,8 @@ func TestTopicPartitionsBalanced(t *testing.T) {
)
require.NoError(t, err)
- var connectedPartitions xatomic.Int64
- var handled xatomic.Int64
+ var connectedPartitions atomic.Int64
+ var handled atomic.Int64
var sessionsMutex sync.Mutex
sessions := map[int64]bool{}
diff --git a/tests/integration/topic_read_writer_test.go b/tests/integration/topic_read_writer_test.go
index c1e10f9f7..0634c4958 100644
--- a/tests/integration/topic_read_writer_test.go
+++ b/tests/integration/topic_read_writer_test.go
@@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -24,7 +25,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/empty"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicsugar"
@@ -163,8 +163,6 @@ func TestMessageMetadata(t *testing.T) {
}
func TestManyConcurentReadersWriters(t *testing.T) {
- xtest.AllowByFlag(t, "ISSUE-389")
-
const partitionCount = 3
const writersCount = 5
const readersCount = 10
@@ -351,8 +349,6 @@ func TestCommitUnexpectedRange(t *testing.T) {
}
func TestUpdateToken(t *testing.T) {
- xtest.AllowByFlag(t, "LOGBROKER-7960")
-
ctx := context.Background()
db := connect(t)
dbLogging := connectWithGrpcLogging(t)
@@ -376,7 +372,7 @@ func TestUpdateToken(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
- stopTopicActivity := xatomic.Bool{}
+ stopTopicActivity := atomic.Bool{}
go func() {
defer wg.Done()
@@ -391,7 +387,7 @@ func TestUpdateToken(t *testing.T) {
}
}()
- hasMessages := xatomic.Bool{}
+ hasMessages := atomic.Bool{}
wg.Add(1)
go func() {
diff --git a/tests/integration/topic_regression_test.go b/tests/integration/topic_regression_test.go
new file mode 100644
index 000000000..fab6cd075
--- /dev/null
+++ b/tests/integration/topic_regression_test.go
@@ -0,0 +1,35 @@
+//go:build integration
+// +build integration
+
+package integration
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
+ "github.com/ydb-platform/ydb-go-sdk/v3/topic/topicwriter"
+)
+
+func TestRegressionIssue1011_WriteInitInfoLastSeqNum(t *testing.T) {
+ scope := newScope(t)
+ w1 := scope.TopicWriter()
+ err := w1.Write(scope.Ctx, topicwriter.Message{
+ Data: strings.NewReader("123"),
+ })
+ require.NoError(t, err)
+ require.NoError(t, w1.Close(scope.Ctx))
+
+ // Check
+ w2, err := scope.Driver().Topic().StartWriter(
+ scope.TopicPath(),
+ topicoptions.WithWriterProducerID(scope.TopicWriterProducerID()),
+ topicoptions.WithWriterSetAutoSeqNo(false),
+ )
+ require.NoError(t, err)
+
+ info, err := w2.WaitInitInfo(scope.Ctx)
+ require.Equal(t, int64(1), info.LastSeqNum)
+}
diff --git a/tests/integration/topic_stress_test.go b/tests/integration/topic_stress_test.go
index e55b7a322..f6044e755 100644
--- a/tests/integration/topic_stress_test.go
+++ b/tests/integration/topic_stress_test.go
@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -18,7 +19,6 @@ import (
"golang.org/x/sync/errgroup"
"github.com/ydb-platform/ydb-go-sdk/v3"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/topic/topicoptions"
@@ -90,7 +90,7 @@ func stressTestInATopic(
writeStatusWriterSeqno := map[string]int64{}
readStatusWriterMaxSeqNo := map[string]int64{}
- var stopWrite xatomic.Bool
+ var stopWrite atomic.Bool
writeToTopic := func(ctx context.Context, producerID string, wg *sync.WaitGroup) (resErr error) {
var writer *topicwriter.Writer
diff --git a/tests/integration/tx_test.go b/tests/integration/tx_test.go
index a3c3db081..3c5666116 100644
--- a/tests/integration/tx_test.go
+++ b/tests/integration/tx_test.go
@@ -138,14 +138,14 @@ func TestNoEffectsIfForgetCommitTx(t *testing.T) {
// check row for NO write
var (
- value string
- errConnAlreadyHaveTx *xsql.ErrConnAlreadyHaveTx
+ value string
+ connAlreadyHaveTxError *xsql.ConnAlreadyHaveTxError
)
err = db.QueryRowContext(ctx, `SELECT val FROM table WHERE id = $1`, id).Scan(&value)
require.ErrorIs(t, err, sql.ErrNoRows)
// second tx on existing conn === session
_, err = cc.BeginTx(ctx, &sql.TxOptions{})
- require.ErrorAs(t, err, &errConnAlreadyHaveTx)
+ require.ErrorAs(t, err, &connAlreadyHaveTxError)
})
}
diff --git a/tests/integration/with_trace_retry_test.go b/tests/integration/with_trace_retry_test.go
index 42bc1958b..1cb5b6564 100644
--- a/tests/integration/with_trace_retry_test.go
+++ b/tests/integration/with_trace_retry_test.go
@@ -26,9 +26,7 @@ func TestWithTraceRetry(t *testing.T) {
scope = newScope(t)
db = scope.Driver(
ydb.WithTraceRetry(trace.Retry{
- OnRetry: func(
- info trace.RetryLoopStartInfo,
- ) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
retryCalled[info.Label] = true
return nil
},
@@ -64,9 +62,7 @@ func TestWithTraceRetry(t *testing.T) {
scope = newScope(t)
nativeDb = scope.Driver(
ydb.WithTraceRetry(trace.Retry{
- OnRetry: func(
- info trace.RetryLoopStartInfo,
- ) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
retryCalled[info.Label] = true
return nil
},
diff --git a/tests/slo/Dockerfile b/tests/slo/Dockerfile
index 743535336..49226b98d 100644
--- a/tests/slo/Dockerfile
+++ b/tests/slo/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.21 as build
+FROM golang:1.22 as build
ARG SRC_PATH
ARG JOB_NAME
COPY . /src
diff --git a/tests/slo/database/sql/storage.go b/tests/slo/database/sql/storage.go
index 0c6bcc606..6468764f0 100755
--- a/tests/slo/database/sql/storage.go
+++ b/tests/slo/database/sql/storage.go
@@ -139,11 +139,9 @@ func (s *Storage) Read(ctx context.Context, entryID generator.RowID) (res genera
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -179,11 +177,9 @@ func (s *Storage) Write(ctx context.Context, e generator.Row) (attempts int, err
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -204,6 +200,7 @@ func (s *Storage) createTable(ctx context.Context) error {
return retry.Do(ydb.WithTxControl(ctx, writeTx), s.db,
func(ctx context.Context, cc *sql.Conn) error {
_, err := s.db.ExecContext(ydb.WithQueryMode(ctx, ydb.SchemeQueryMode), s.createQuery)
+
return err
}, retry.WithIdempotent(true),
)
@@ -220,6 +217,7 @@ func (s *Storage) dropTable(ctx context.Context) error {
return retry.Do(ydb.WithTxControl(ctx, writeTx), s.db,
func(ctx context.Context, cc *sql.Conn) error {
_, err := s.db.ExecContext(ydb.WithQueryMode(ctx, ydb.SchemeQueryMode), s.dropQuery)
+
return err
}, retry.WithIdempotent(true),
)
diff --git a/tests/slo/go.mod b/tests/slo/go.mod
index 35a9ce667..e8f010142 100644
--- a/tests/slo/go.mod
+++ b/tests/slo/go.mod
@@ -1,12 +1,13 @@
module slo
-go 1.20
+go 1.21
require (
github.com/prometheus/client_golang v1.14.0
github.com/ydb-platform/gorm-driver v0.1.1
- github.com/ydb-platform/ydb-go-sdk/v3 v3.49.0
- golang.org/x/sync v0.3.0
+ github.com/ydb-platform/ydb-go-sdk/v3 v3.58.0
+ go.opentelemetry.io/otel v1.21.0
+ golang.org/x/sync v0.6.0
golang.org/x/time v0.3.0
gorm.io/gorm v1.25.1
xorm.io/xorm v1.3.2
@@ -15,16 +16,19 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
- github.com/google/uuid v1.3.0 // indirect
+ github.com/google/uuid v1.5.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -33,22 +37,24 @@ require (
github.com/prometheus/procfs v0.8.0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20230403093326-123923969dc6 // indirect
- github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a // indirect
+ github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf // indirect
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.2.0 // indirect
github.com/ydb-platform/ydb-go-yc v0.10.2 // indirect
github.com/ydb-platform/ydb-go-yc-metadata v0.5.3 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sys v0.12.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
- google.golang.org/grpc v1.57.1 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
+ go.opentelemetry.io/otel/metric v1.21.0 // indirect
+ go.opentelemetry.io/otel/trace v1.21.0 // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
+ google.golang.org/grpc v1.60.1 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
modernc.org/sqlite v1.24.0 // indirect
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
)
replace github.com/ydb-platform/ydb-go-sdk/v3 => ../../.
-replace xorm.io/xorm => github.com/ydb-platform/xorm v0.0.6
+replace xorm.io/xorm => github.com/ydb-platform/xorm v0.0.3
diff --git a/tests/slo/go.sum b/tests/slo/go.sum
index e12fb847f..78bb98723 100644
--- a/tests/slo/go.sum
+++ b/tests/slo/go.sum
@@ -598,14 +598,16 @@ git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3p
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
-github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
@@ -619,13 +621,25 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
@@ -635,11 +649,9 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -655,18 +667,31 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
-github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
+github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -682,8 +707,11 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
@@ -696,6 +724,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
@@ -704,16 +733,26 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
-github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
-github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
@@ -721,11 +760,11 @@ github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
-github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -737,7 +776,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -780,8 +818,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -803,11 +842,12 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
+github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
@@ -826,77 +866,119 @@ github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57Q
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
+github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
+github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
-github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
-github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
-github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
-github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
-github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
+github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
+github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
+github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE=
+github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
-github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
-github.com/jackc/pgx/v4 v4.18.0/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
+github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
+github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
+github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
+github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
@@ -916,26 +998,44 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
-github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -943,56 +1043,93 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
-github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
-github.com/rekby/fixenv v0.3.2/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rekby/fixenv v0.6.1 h1:jUFiSPpajT4WY2cYuc++7Y1zWrnCxnovGCIX72PZniM=
+github.com/rekby/fixenv v0.6.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
@@ -1000,20 +1137,34 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -1030,17 +1181,22 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yandex-cloud/go-genproto v0.0.0-20211115083454-9ca41db5ed9e/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
github.com/yandex-cloud/go-genproto v0.0.0-20230403093326-123923969dc6 h1:BkuaOCK1nc1eHSb/jCMwM2JZR00lJ9xNvnHvsZQgbRc=
github.com/yandex-cloud/go-genproto v0.0.0-20230403093326-123923969dc6/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
github.com/ydb-platform/gorm-driver v0.1.1 h1:PkN+sGSJehOZn9jQIFEmAOfhE73FNDMq+uzsnf7LVAM=
github.com/ydb-platform/gorm-driver v0.1.1/go.mod h1:Zv368SD5tHqkblmaOG6r2KTvtSIzPuB5p8rBaE6wVmw=
-github.com/ydb-platform/xorm v0.0.6 h1:mlclMIXR7Obwho3cYIIgBoMlMZ+APJZ9gnJQICyVAYY=
-github.com/ydb-platform/xorm v0.0.6/go.mod h1:vLAI6Xqpa+48y9I9HJnjD6IDKp/GnATYbtDgWzQb88c=
-github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a h1:9wx+kCrCQCdwmDe1AFW5yAHdzlo+RV7lcy6y7Zq661s=
-github.com/ydb-platform/ydb-go-genproto v0.0.0-20231215113745-46f6d30f974a/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
+github.com/ydb-platform/xorm v0.0.3 h1:MXk42lANB6r/MMLg/XdJfyXJycGUDlCeLiMlLGDKVPw=
+github.com/ydb-platform/xorm v0.0.3/go.mod h1:hFsU7EUF0o3S+l5c0eyP2yPVjJ0d4gsFdqCsyazzwBc=
+github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf h1:ckwNHVo4bv2tqNkgx3W3HANh3ta1j6TR5qw08J1A7Tw=
+github.com/ydb-platform/ydb-go-genproto v0.0.0-20240126124512-dbb0e1720dbf/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.2.0 h1:IG5bPd+Lqyc+zsw2kmxqfGLkaDHuAEnWX63/8RBBiA4=
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.2.0/go.mod h1:l6lZ+osdQOjDRBgRA4PQ06BuvmXN2neYjnRw8rCfd7s=
github.com/ydb-platform/ydb-go-yc v0.10.2 h1:RAHy6g7ncxk1y0N4oS2MwYXLATqRqKBI6DYXuxpV2wo=
@@ -1059,6 +1215,10 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -1067,6 +1227,12 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
+go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
+go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
+go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
+go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
+go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
@@ -1074,6 +1240,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
+go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -1082,22 +1250,25 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1153,15 +1324,21 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
+golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -1198,10 +1375,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -1214,6 +1389,7 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
@@ -1222,8 +1398,9 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1269,12 +1446,17 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1287,9 +1469,11 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1311,6 +1495,7 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1334,6 +1519,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1344,7 +1530,6 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1357,6 +1542,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1364,11 +1550,13 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
@@ -1393,8 +1581,10 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1402,7 +1592,9 @@ golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1410,6 +1602,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -1465,6 +1658,7 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
@@ -1487,6 +1681,7 @@ gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6d
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1545,6 +1740,7 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@@ -1556,6 +1752,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
@@ -1672,6 +1869,7 @@ google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ
google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230131230820-1c016267d619/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
@@ -1683,18 +1881,26 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl
google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY=
-google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
+google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg=
+google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8=
-google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
+google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo=
+google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@@ -1731,8 +1937,9 @@ google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsA
google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
-google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg=
google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
+google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
+google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1751,35 +1958,39 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1791,70 +2002,150 @@ honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
+modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
-modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
-modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
-modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI=
-modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0=
+modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
+modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw=
+modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI=
+modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag=
+modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw=
+modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ=
+modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c=
+modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo=
+modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg=
+modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I=
+modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs=
+modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8=
+modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE=
+modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk=
+modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w=
+modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE=
+modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8=
+modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc=
+modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU=
+modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE=
+modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk=
+modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI=
+modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE=
+modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg=
+modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74=
+modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU=
+modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
+modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
+modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
+modernc.org/ccgo/v3 v3.12.65/go.mod h1:D6hQtKxPNZiY6wDBtehSGKFKmyXn53F8nGTpH+POmS4=
+modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
+modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
+modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
+modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
+modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws=
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
-modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
+modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
+modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
+modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
+modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
+modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M=
+modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU=
+modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE=
+modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso=
+modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8=
+modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8=
+modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I=
+modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk=
+modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY=
+modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE=
+modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg=
+modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM=
+modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg=
+modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo=
+modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8=
+modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ=
+modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA=
+modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM=
+modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg=
+modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE=
+modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM=
+modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU=
+modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw=
+modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
+modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
+modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
+modernc.org/libc v1.11.70/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
+modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
+modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
+modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
+modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
+modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
-modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA=
-modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0=
-modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
-modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
-modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
-modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
+modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
+modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
+modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
-modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
-modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
+modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
-modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI=
modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
+modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY=
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
-modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
-modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 h1:bvLlAPW1ZMTWA32LuZMBEGHAUOcATZjzHcotf3SWweM=
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
diff --git a/tests/slo/gorm/storage.go b/tests/slo/gorm/storage.go
index 2481014f1..b2cf92211 100644
--- a/tests/slo/gorm/storage.go
+++ b/tests/slo/gorm/storage.go
@@ -110,11 +110,9 @@ func (s *Storage) Read(ctx context.Context, id generator.RowID) (r generator.Row
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -158,11 +156,9 @@ func (s *Storage) Write(ctx context.Context, row generator.Row) (attempts int, e
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
diff --git a/tests/slo/internal/config/config.go b/tests/slo/internal/config/config.go
index 530e412e8..b858d27b8 100644
--- a/tests/slo/internal/config/config.go
+++ b/tests/slo/internal/config/config.go
@@ -40,6 +40,7 @@ func New() (*Config, error) {
if len(os.Args) < 2 {
fmt.Print(mainHelp)
+
return nil, ErrWrongArgs
}
@@ -49,6 +50,7 @@ func New() (*Config, error) {
case "create":
if len(os.Args) < 4 {
fmt.Print(createHelp)
+
return nil, ErrWrongArgs
}
@@ -69,6 +71,7 @@ func New() (*Config, error) {
case "cleanup":
if len(os.Args) < 4 {
fmt.Print(cleanupHelp)
+
return nil, ErrWrongArgs
}
@@ -77,6 +80,7 @@ func New() (*Config, error) {
case "run":
if len(os.Args) < 4 {
fmt.Print(runHelp)
+
return nil, ErrWrongArgs
}
@@ -98,6 +102,7 @@ func New() (*Config, error) {
fs.IntVar(&cfg.ShutdownTime, "shutdown-time", 30, "time to wait before force kill workers")
default:
fmt.Print(mainHelp)
+
return nil, ErrWrongArgs
}
diff --git a/tests/slo/internal/generator/row.go b/tests/slo/internal/generator/row.go
index 7a2d6aa2b..2eb2c1fc7 100644
--- a/tests/slo/internal/generator/row.go
+++ b/tests/slo/internal/generator/row.go
@@ -4,11 +4,12 @@ import "time"
type RowID = uint64
+//nolint:tagalign
type Row struct {
- Hash uint64 `gorm:"column:hash;primarykey;autoIncrement:false" xorm:"pk 'hash'"`
- ID RowID `gorm:"column:id;primarykey;autoIncrement:false" xorm:"pk 'id'"` //nolint:tagalign
- PayloadStr *string `gorm:"column:payload_str" xorm:"'payload_str'"` //nolint:tagalign
- PayloadDouble *float64 `gorm:"column:payload_double" xorm:"'payload_double'"` //nolint:tagalign
- PayloadTimestamp *time.Time `gorm:"column:payload_timestamp" xorm:"'payload_timestamp'"` //nolint:tagalign
- PayloadHash uint64 `gorm:"column:payload_hash" xorm:"'payload_hash'"` //nolint:tagalign
+ Hash uint64 `sql:"hash" gorm:"column:hash;primarykey;autoIncrement:false" xorm:"pk 'hash'"`
+ ID RowID `sql:"id" gorm:"column:id;primarykey;autoIncrement:false" xorm:"pk 'id'"`
+ PayloadStr *string `sql:"payload_str" gorm:"column:payload_str" xorm:"'payload_str'"`
+ PayloadDouble *float64 `sql:"payload_double" gorm:"column:payload_double" xorm:"'payload_double'"`
+ PayloadTimestamp *time.Time `sql:"payload_timestamp" gorm:"column:payload_timestamp" xorm:"'payload_timestamp'"`
+ PayloadHash uint64 `sql:"payload_hash" gorm:"column:payload_hash" xorm:"'payload_hash'"`
}
diff --git a/tests/slo/internal/workers/workers.go b/tests/slo/internal/workers/workers.go
index 64eb7da79..3aacf2b22 100644
--- a/tests/slo/internal/workers/workers.go
+++ b/tests/slo/internal/workers/workers.go
@@ -24,6 +24,7 @@ func New(cfg *config.Config, s ReadWriter, label, jobName string) (*Workers, err
m, err := metrics.New(cfg.PushGateway, label, jobName)
if err != nil {
fmt.Printf("create metrics failed: %v\n", err)
+
return nil, err
}
diff --git a/tests/slo/internal/workers/write.go b/tests/slo/internal/workers/write.go
index daa624174..e9c7b7cae 100644
--- a/tests/slo/internal/workers/write.go
+++ b/tests/slo/internal/workers/write.go
@@ -28,6 +28,7 @@ func (w *Workers) write(ctx context.Context, gen *generator.Generator) (err erro
row, err = gen.Generate()
if err != nil {
fmt.Printf("generate error: %v\n", err)
+
return err
}
diff --git a/tests/slo/native/query/main.go b/tests/slo/native/query/main.go
new file mode 100644
index 000000000..138187877
--- /dev/null
+++ b/tests/slo/native/query/main.go
@@ -0,0 +1,139 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+
+ "golang.org/x/sync/errgroup"
+ "golang.org/x/time/rate"
+
+ "slo/internal/config"
+ "slo/internal/generator"
+ "slo/internal/workers"
+)
+
+var (
+ label string
+ jobName string
+)
+
+func main() {
+ ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)
+ defer cancel()
+
+ cfg, err := config.New()
+ if err != nil {
+ panic(fmt.Errorf("create config failed: %w", err))
+ }
+
+ fmt.Println("program started")
+ defer fmt.Println("program finished")
+
+ ctx, cancel = context.WithTimeout(ctx, time.Duration(cfg.Time)*time.Second)
+ defer cancel()
+
+ s, err := NewStorage(ctx, cfg, cfg.ReadRPS+cfg.WriteRPS)
+ if err != nil {
+ panic(fmt.Errorf("create storage failed: %w", err))
+ }
+ defer func() {
+ var (
+ shutdownCtx context.Context
+ shutdownCancel context.CancelFunc
+ )
+ if cfg.ShutdownTime > 0 {
+ shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(),
+ time.Duration(cfg.ShutdownTime)*time.Second)
+ } else {
+ shutdownCtx, shutdownCancel = context.WithCancel(context.Background())
+ }
+ defer shutdownCancel()
+
+ _ = s.close(shutdownCtx)
+ }()
+
+ fmt.Println("db init ok")
+
+ switch cfg.Mode {
+ case config.CreateMode:
+ err = s.createTable(ctx)
+ if err != nil {
+ panic(fmt.Errorf("create table failed: %w", err))
+ }
+ fmt.Println("create table ok")
+
+ gen := generator.New(0)
+
+ g := errgroup.Group{}
+
+ for i := uint64(0); i < cfg.InitialDataCount; i++ {
+ g.Go(func() (err error) {
+ e, err := gen.Generate()
+ if err != nil {
+ return err
+ }
+
+ _, err = s.Write(ctx, e)
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+ }
+
+ err = g.Wait()
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println("entries write ok")
+ case config.CleanupMode:
+ err = s.dropTable(ctx)
+ if err != nil {
+ panic(fmt.Errorf("create table failed: %w", err))
+ }
+
+ fmt.Println("cleanup table ok")
+ case config.RunMode:
+ gen := generator.New(cfg.InitialDataCount)
+
+ w, err := workers.New(cfg, s, label, jobName)
+ if err != nil {
+ panic(fmt.Errorf("create workers failed: %w", err))
+ }
+ defer func() {
+ err := w.Close()
+ if err != nil {
+ panic(fmt.Errorf("workers close failed: %w", err))
+ }
+ fmt.Println("workers close ok")
+ }()
+
+ wg := sync.WaitGroup{}
+
+ readRL := rate.NewLimiter(rate.Limit(cfg.ReadRPS), 1)
+ wg.Add(cfg.ReadRPS)
+ for i := 0; i < cfg.ReadRPS; i++ {
+ go w.Read(ctx, &wg, readRL)
+ }
+
+ writeRL := rate.NewLimiter(rate.Limit(cfg.WriteRPS), 1)
+ wg.Add(cfg.WriteRPS)
+ for i := 0; i < cfg.WriteRPS; i++ {
+ go w.Write(ctx, &wg, writeRL, gen)
+ }
+
+ metricsRL := rate.NewLimiter(rate.Every(time.Duration(cfg.ReportPeriod)*time.Millisecond), 1)
+ wg.Add(1)
+ go w.Metrics(ctx, &wg, metricsRL)
+
+ wg.Wait()
+ default:
+ panic(fmt.Errorf("unknown mode: %v", cfg.Mode))
+ }
+}
diff --git a/tests/slo/native/query/storage.go b/tests/slo/native/query/storage.go
new file mode 100755
index 000000000..89377d012
--- /dev/null
+++ b/tests/slo/native/query/storage.go
@@ -0,0 +1,269 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "time"
+
+ ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/log"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+
+ "slo/internal/config"
+ "slo/internal/generator"
+)
+
+type Storage struct {
+ db *ydb.Driver
+ cfg *config.Config
+ tablePath string
+}
+
+const writeQuery = `
+DECLARE $id AS Uint64;
+DECLARE $payload_str AS Utf8;
+DECLARE $payload_double AS Double;
+DECLARE $payload_timestamp AS Timestamp;
+
+UPSERT INTO %s (
+ id, hash, payload_str, payload_double, payload_timestamp
+) VALUES (
+ $id, Digest::NumericHash($id), $payload_str, $payload_double, $payload_timestamp
+);
+`
+
+const readQuery = `
+DECLARE $id AS Uint64;
+SELECT id, payload_str, payload_double, payload_timestamp, payload_hash
+FROM %s WHERE id = $id AND hash = Digest::NumericHash($id);
+`
+
+const createTableQuery = `
+CREATE TABLE IF NOT EXISTS %s (
+ hash Uint64?,
+ id Uint64?,
+ payload_str Text?,
+ payload_double Double?,
+ payload_timestamp Timestamp?,
+ payload_hash Uint64?,
+ PRIMARY KEY (hash, id)
+) WITH (
+ UNIFORM_PARTITIONS = %d,
+ AUTO_PARTITIONING_BY_SIZE = ENABLED,
+ AUTO_PARTITIONING_PARTITION_SIZE_MB = %d,
+ AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = %d,
+ AUTO_PARTITIONING_MAX_PARTITIONS_COUNT = %d
+)
+`
+
+const dropTableQuery = `
+DROP TABLE %s
+`
+
+func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (*Storage, error) {
+ ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
+ defer cancel()
+
+ db, err := ydb.Open(ctx,
+ cfg.Endpoint+cfg.DB,
+ ydb.WithSessionPoolSizeLimit(poolSize),
+ ydb.WithLogger(log.Default(os.Stderr, log.WithMinLevel(log.ERROR)), trace.DetailsAll),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ prefix := path.Join(db.Name(), label)
+
+ s := &Storage{
+ db: db,
+ cfg: cfg,
+ tablePath: "`" + path.Join(prefix, cfg.Table) + "`",
+ }
+
+ return s, nil
+}
+
+func (s *Storage) Read(ctx context.Context, entryID generator.RowID) (_ generator.Row, attempts int, finalErr error) {
+ if err := ctx.Err(); err != nil {
+ return generator.Row{}, attempts, err
+ }
+
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(s.cfg.ReadTimeout)*time.Millisecond)
+ defer cancel()
+
+ e := generator.Row{}
+
+ err := s.db.Query().Do(ctx,
+ func(ctx context.Context, session query.Session) (err error) {
+ if err = ctx.Err(); err != nil {
+ return err
+ }
+
+ _, res, err := session.Execute(ctx,
+ fmt.Sprintf(readQuery, s.tablePath),
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$id").Uint64(entryID).
+ Build(),
+ ),
+ query.WithTxControl(query.TxControl(
+ query.BeginTx(query.WithOnlineReadOnly()),
+ query.CommitTx(),
+ )),
+ )
+ if err != nil {
+ return err
+ }
+ defer func() {
+ _ = res.Close(ctx)
+ }()
+
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return nil
+ }
+
+ return err
+ }
+
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return nil
+ }
+
+ return err
+ }
+
+ err = row.ScanStruct(&e, query.WithScanStructAllowMissingColumnsFromSelect())
+ if err != nil {
+ return err
+ }
+
+ return res.Err()
+ },
+ query.WithIdempotent(),
+ query.WithTrace(&trace.Query{
+ OnDo: func(info trace.QueryDoStartInfo) func(trace.QueryDoDoneInfo) {
+ return func(info trace.QueryDoDoneInfo) {
+ attempts = info.Attempts
+ }
+ },
+ }),
+ query.WithLabel("READ"),
+ )
+
+ return e, attempts, err
+}
+
+func (s *Storage) Write(ctx context.Context, e generator.Row) (attempts int, finalErr error) {
+ if err := ctx.Err(); err != nil {
+ return attempts, err
+ }
+
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(s.cfg.WriteTimeout)*time.Millisecond)
+ defer cancel()
+
+ err := s.db.Query().Do(ctx,
+ func(ctx context.Context, session query.Session) (err error) {
+ if err = ctx.Err(); err != nil {
+ return err
+ }
+
+ _, res, err := session.Execute(ctx,
+ fmt.Sprintf(writeQuery, s.tablePath),
+ query.WithParameters(
+ ydb.ParamsBuilder().
+ Param("$id").Uint64(e.ID).
+ Param("$payload_str").Text(*e.PayloadStr).
+ Param("$payload_double").Double(*e.PayloadDouble).
+ Param("$payload_timestamp").Timestamp(*e.PayloadTimestamp).
+ Build(),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ _ = res.Close(ctx)
+ }()
+
+ return res.Err()
+ },
+ query.WithIdempotent(),
+ query.WithTrace(&trace.Query{
+ OnDo: func(info trace.QueryDoStartInfo) func(trace.QueryDoDoneInfo) {
+ return func(info trace.QueryDoDoneInfo) {
+ attempts = info.Attempts
+ }
+ },
+ }),
+ query.WithLabel("WRITE"),
+ )
+
+ return attempts, err
+}
+
+func (s *Storage) createTable(ctx context.Context) error {
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(s.cfg.WriteTimeout)*time.Millisecond)
+ defer cancel()
+
+ return s.db.Query().Do(ctx,
+ func(ctx context.Context, session query.Session) error {
+ _, _, err := session.Execute(ctx,
+ fmt.Sprintf(createTableQuery, s.tablePath, s.cfg.MinPartitionsCount, s.cfg.PartitionSize,
+ s.cfg.MinPartitionsCount, s.cfg.MaxPartitionsCount,
+ ),
+ query.WithTxControl(query.NoTx()))
+
+ return err
+ }, query.WithIdempotent(),
+ query.WithLabel("CREATE TABLE"),
+ )
+}
+
+func (s *Storage) dropTable(ctx context.Context) error {
+ err := ctx.Err()
+ if err != nil {
+ return err
+ }
+
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(s.cfg.WriteTimeout)*time.Millisecond)
+ defer cancel()
+
+ return s.db.Query().Do(ctx,
+ func(ctx context.Context, session query.Session) error {
+ _, _, err := session.Execute(ctx,
+ fmt.Sprintf(dropTableQuery, s.tablePath),
+ query.WithTxControl(query.NoTx()),
+ )
+
+ return err
+ },
+ query.WithIdempotent(),
+ query.WithLabel("DROP TABLE"),
+ )
+}
+
+func (s *Storage) close(ctx context.Context) error {
+ var (
+ shutdownCtx context.Context
+ shutdownCancel context.CancelFunc
+ )
+ if s.cfg.ShutdownTime > 0 {
+ shutdownCtx, shutdownCancel = context.WithTimeout(ctx, time.Duration(s.cfg.ShutdownTime)*time.Second)
+ } else {
+ shutdownCtx, shutdownCancel = context.WithCancel(ctx)
+ }
+ defer shutdownCancel()
+
+ return s.db.Close(shutdownCtx)
+}
diff --git a/tests/slo/native/main.go b/tests/slo/native/table/main.go
similarity index 100%
rename from tests/slo/native/main.go
rename to tests/slo/native/table/main.go
diff --git a/tests/slo/native/storage.go b/tests/slo/native/table/storage.go
similarity index 91%
rename from tests/slo/native/storage.go
rename to tests/slo/native/table/storage.go
index 4a438bf10..b31f72a0e 100755
--- a/tests/slo/native/storage.go
+++ b/tests/slo/native/table/storage.go
@@ -142,11 +142,9 @@ func (s *Storage) Read(ctx context.Context, entryID generator.RowID) (_ generato
},
table.WithIdempotent(),
table.WithTrace(trace.Table{
- OnDo: func(info trace.TableDoStartInfo) func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoDoneInfo) {
- attempts = info.Attempts
- }
+ OnDo: func(info trace.TableDoStartInfo) func(trace.TableDoDoneInfo) {
+ return func(info trace.TableDoDoneInfo) {
+ attempts = info.Attempts
}
},
}),
@@ -190,11 +188,9 @@ func (s *Storage) Write(ctx context.Context, e generator.Row) (attempts int, _ e
},
table.WithIdempotent(),
table.WithTrace(trace.Table{
- OnDo: func(info trace.TableDoStartInfo) func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoDoneInfo) {
- attempts = info.Attempts
- }
+ OnDo: func(info trace.TableDoStartInfo) func(trace.TableDoDoneInfo) {
+ return func(info trace.TableDoDoneInfo) {
+ attempts = info.Attempts
}
},
}),
diff --git a/tests/slo/xorm/storage.go b/tests/slo/xorm/storage.go
index b6bc813df..4550374c9 100644
--- a/tests/slo/xorm/storage.go
+++ b/tests/slo/xorm/storage.go
@@ -141,11 +141,9 @@ func (s *Storage) Read(ctx context.Context, id generator.RowID) (row generator.R
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -170,16 +168,15 @@ func (s *Storage) Write(ctx context.Context, row generator.Row) (attempts int, e
}
_, err = s.x.Context(ctx).SetExpr("hash", fmt.Sprintf("Digest::NumericHash(%d)", row.ID)).Insert(row)
+
return err
},
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
diff --git a/testutil/compare.go b/testutil/compare.go
index 5e56caf94..a021ff909 100644
--- a/testutil/compare.go
+++ b/testutil/compare.go
@@ -29,34 +29,36 @@ var ErrNotComparable = xerrors.Wrap(fmt.Errorf("not comparable"))
func Compare(l, r value.Value) (int, error) {
a := allocator.New()
defer a.Free()
+
return compare(unwrapTypedValue(value.ToYDB(l, a)), unwrapTypedValue(value.ToYDB(r, a)))
}
func unwrapTypedValue(v *Ydb.TypedValue) *Ydb.TypedValue {
- typ := v.Type
- val := v.Value
+ typ := v.GetType()
+ val := v.GetValue()
for opt := typ.GetOptionalType(); opt != nil; opt = typ.GetOptionalType() {
- typ = opt.Item
+ typ = opt.GetItem()
if nested := val.GetNestedValue(); nested != nil {
val = nested
}
}
+
return &Ydb.TypedValue{Type: typ, Value: val}
}
func compare(lhs, rhs *Ydb.TypedValue) (int, error) {
- lTypeID := lhs.Type.GetTypeId()
- rTypeID := rhs.Type.GetTypeId()
+ lTypeID := lhs.GetType().GetTypeId()
+ rTypeID := rhs.GetType().GetTypeId()
switch {
case lTypeID != rTypeID:
return 0, notComparableError(lhs, rhs)
case lTypeID != Ydb.Type_PRIMITIVE_TYPE_ID_UNSPECIFIED:
- return comparePrimitives(lTypeID, lhs.Value, rhs.Value)
- case lhs.Type.GetTupleType() != nil && rhs.Type.GetTupleType() != nil:
+ return comparePrimitives(lTypeID, lhs.GetValue(), rhs.GetValue())
+ case lhs.GetType().GetTupleType() != nil && rhs.GetType().GetTupleType() != nil:
return compareTuplesOrLists(expandTuple(lhs), expandTuple(rhs))
- case lhs.Type.GetListType() != nil && rhs.Type.GetListType() != nil:
+ case lhs.GetType().GetListType() != nil && rhs.GetType().GetListType() != nil:
return compareTuplesOrLists(expandList(lhs), expandList(rhs))
- case lhs.Type.GetStructType() != nil && rhs.Type.GetStructType() != nil:
+ case lhs.GetType().GetStructType() != nil && rhs.GetType().GetStructType() != nil:
return compareStructs(expandStruct(lhs), expandStruct(rhs))
default:
return 0, notComparableError(lhs, rhs)
@@ -69,6 +71,7 @@ func expandItems(v *Ydb.TypedValue, itemType func(i int) *Ydb.Type) []*Ydb.Typed
for i, val := range v.GetValue().GetItems() {
values = append(values, unwrapTypedValue(&Ydb.TypedValue{Type: itemType(i), Value: val}))
}
+
return values
}
@@ -85,12 +88,13 @@ func expandStruct(v *Ydb.TypedValue) []*Ydb.TypedValue {
}
func expandTuple(v *Ydb.TypedValue) []*Ydb.TypedValue {
- tuple := v.Type.GetTupleType()
- size := len(tuple.Elements)
+ tuple := v.GetType().GetTupleType()
+ size := len(tuple.GetElements())
values := make([]*Ydb.TypedValue, 0, size)
- for idx, typ := range tuple.Elements {
- values = append(values, unwrapTypedValue(&Ydb.TypedValue{Type: typ, Value: v.Value.Items[idx]}))
+ for idx, typ := range tuple.GetElements() {
+ values = append(values, unwrapTypedValue(&Ydb.TypedValue{Type: typ, Value: v.GetValue().GetItems()[idx]}))
}
+
return values
}
@@ -99,12 +103,13 @@ func notComparableError(lhs, rhs interface{}) error {
}
func comparePrimitives(t Ydb.Type_PrimitiveTypeId, lhs, rhs *Ydb.Value) (int, error) {
- _, lIsNull := lhs.Value.(*Ydb.Value_NullFlagValue)
- _, rIsNull := rhs.Value.(*Ydb.Value_NullFlagValue)
+ _, lIsNull := lhs.GetValue().(*Ydb.Value_NullFlagValue)
+ _, rIsNull := rhs.GetValue().(*Ydb.Value_NullFlagValue)
if lIsNull {
if rIsNull {
return 0, nil
}
+
return -1, nil
}
if rIsNull {
@@ -142,6 +147,7 @@ func compareTuplesOrLists(lhs, rhs []*Ydb.TypedValue) (int, error) {
if len(rhs) > len(lhs) {
return -1, nil
}
+
return 0, nil
}
@@ -164,6 +170,7 @@ func compareStructs(lhs, rhs []*Ydb.TypedValue) (int, error) {
if len(rhs) > len(lhs) {
return -1, nil
}
+
return 0, nil
}
@@ -271,12 +278,14 @@ func compareDouble(l, r *Ydb.Value) int {
func compareText(l, r *Ydb.Value) int {
ll := l.GetTextValue()
rr := r.GetTextValue()
+
return strings.Compare(ll, rr)
}
func compareBytes(l, r *Ydb.Value) int {
ll := l.GetBytesValue()
rr := r.GetBytesValue()
+
return bytes.Compare(ll, rr)
}
@@ -287,11 +296,13 @@ func compareBool(l, r *Ydb.Value) int {
if rr {
return 0
}
+
return 1
}
if rr {
return -1
}
+
return 0
}
@@ -306,6 +317,7 @@ func compareDyNumber(l, r *Ydb.Value) (int, error) {
if err != nil {
return 0, err
}
+
return lf.Cmp(rf), nil
}
diff --git a/testutil/compare_test.go b/testutil/compare_test.go
index 5041b1b74..45f2ed2c1 100644
--- a/testutil/compare_test.go
+++ b/testutil/compare_test.go
@@ -8,8 +8,8 @@ import (
"google.golang.org/protobuf/types/known/structpb"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
- "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
)
func TestUnwrapOptionalValue(t *testing.T) {
@@ -17,11 +17,11 @@ func TestUnwrapOptionalValue(t *testing.T) {
defer a.Free()
v := value.OptionalValue(value.OptionalValue(value.TextValue("a")))
val := unwrapTypedValue(value.ToYDB(v, a))
- typeID := val.Type.GetTypeId()
+ typeID := val.GetType().GetTypeId()
if typeID != Ydb.Type_UTF8 {
t.Errorf("Types are different: expected %d, actual %d", Ydb.Type_UTF8, typeID)
}
- textValue := val.Value.Value.(*Ydb.Value_TextValue)
+ textValue := val.GetValue().GetValue().(*Ydb.Value_TextValue)
text := textValue.TextValue
if text != "a" {
t.Errorf("Values are different: expected %q, actual %q", "a", text)
@@ -33,11 +33,11 @@ func TestUnwrapPrimitiveValue(t *testing.T) {
defer a.Free()
v := value.TextValue("a")
val := unwrapTypedValue(value.ToYDB(v, a))
- typeID := val.Type.GetTypeId()
+ typeID := val.GetType().GetTypeId()
if typeID != Ydb.Type_UTF8 {
t.Errorf("Types are different: expected %d, actual %d", Ydb.Type_UTF8, typeID)
}
- textValue := val.Value.Value.(*Ydb.Value_TextValue)
+ textValue := val.GetValue().GetValue().(*Ydb.Value_TextValue)
text := textValue.TextValue
if text != "a" {
t.Errorf("Values are different: expected %q, actual %q", "a", text)
@@ -47,21 +47,21 @@ func TestUnwrapPrimitiveValue(t *testing.T) {
func TestUnwrapNullValue(t *testing.T) {
a := allocator.New()
defer a.Free()
- v := value.NullValue(value.TypeText)
+ v := value.NullValue(types.Text)
val := unwrapTypedValue(value.ToYDB(v, a))
- typeID := val.Type.GetTypeId()
+ typeID := val.GetType().GetTypeId()
if typeID != Ydb.Type_UTF8 {
t.Errorf("Types are different: expected %d, actual %d", Ydb.Type_UTF8, typeID)
}
- nullFlagValue := val.Value.Value.(*Ydb.Value_NullFlagValue)
+ nullFlagValue := val.GetValue().GetValue().(*Ydb.Value_NullFlagValue)
if nullFlagValue.NullFlagValue != structpb.NullValue_NULL_VALUE {
t.Errorf("Values are different: expected %d, actual %d", structpb.NullValue_NULL_VALUE, nullFlagValue.NullFlagValue)
}
}
func TestUint8(t *testing.T) {
- l := types.Uint8Value(byte(1))
- r := types.Uint8Value(byte(10))
+ l := value.Uint8Value(byte(1))
+ r := value.Uint8Value(byte(10))
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -76,8 +76,8 @@ func TestUint8(t *testing.T) {
}
func TestInt8(t *testing.T) {
- l := types.Int8Value(int8(1))
- r := types.Int8Value(int8(10))
+ l := value.Int8Value(int8(1))
+ r := value.Int8Value(int8(10))
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -92,8 +92,8 @@ func TestInt8(t *testing.T) {
}
func TestTimestamp(t *testing.T) {
- l := types.TimestampValue(1)
- r := types.TimestampValue(10)
+ l := value.TimestampValue(1)
+ r := value.TimestampValue(10)
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -108,8 +108,8 @@ func TestTimestamp(t *testing.T) {
}
func TestDateTime(t *testing.T) {
- l := types.DatetimeValue(1)
- r := types.DatetimeValue(10)
+ l := value.DatetimeValue(1)
+ r := value.DatetimeValue(10)
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -124,8 +124,8 @@ func TestDateTime(t *testing.T) {
}
func TestUint64(t *testing.T) {
- l := types.Uint64Value(uint64(1))
- r := types.Uint64Value(uint64(10))
+ l := value.Uint64Value(uint64(1))
+ r := value.Uint64Value(uint64(10))
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -140,8 +140,8 @@ func TestUint64(t *testing.T) {
}
func TestInt64(t *testing.T) {
- l := types.Int64Value(int64(1))
- r := types.Int64Value(int64(10))
+ l := value.Int64Value(int64(1))
+ r := value.Int64Value(int64(10))
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -156,8 +156,8 @@ func TestInt64(t *testing.T) {
}
func TestDouble(t *testing.T) {
- l := types.DoubleValue(1.0)
- r := types.DoubleValue(2.0)
+ l := value.DoubleValue(1.0)
+ r := value.DoubleValue(2.0)
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -172,8 +172,8 @@ func TestDouble(t *testing.T) {
}
func TestFloat(t *testing.T) {
- l := types.FloatValue(1.0)
- r := types.FloatValue(2.0)
+ l := value.FloatValue(1.0)
+ r := value.FloatValue(2.0)
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -188,8 +188,8 @@ func TestFloat(t *testing.T) {
}
func TestUTF8(t *testing.T) {
- l := types.TextValue("abc")
- r := types.TextValue("abx")
+ l := value.TextValue("abc")
+ r := value.TextValue("abx")
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -204,8 +204,8 @@ func TestUTF8(t *testing.T) {
}
func TestOptionalUTF8(t *testing.T) {
- l := types.OptionalValue(types.OptionalValue(types.TextValue("abc")))
- r := types.TextValue("abx")
+ l := value.OptionalValue(value.OptionalValue(value.TextValue("abc")))
+ r := value.TextValue("abx")
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -220,8 +220,8 @@ func TestOptionalUTF8(t *testing.T) {
}
func TestBytes(t *testing.T) {
- l := types.BytesValue([]byte{1, 2, 3})
- r := types.BytesValue([]byte{1, 2, 5})
+ l := value.BytesValue([]byte{1, 2, 3})
+ r := value.BytesValue([]byte{1, 2, 5})
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -236,8 +236,8 @@ func TestBytes(t *testing.T) {
}
func TestNull(t *testing.T) {
- l := types.NullValue(types.TypeText)
- r := types.TextValue("abc")
+ l := value.NullValue(types.Text)
+ r := value.TextValue("abc")
c, err := Compare(l, r)
requireNoError(t, err)
@@ -253,10 +253,10 @@ func TestNull(t *testing.T) {
}
func TestTuple(t *testing.T) {
- withNull := types.TupleValue(types.Uint64Value(1), types.NullValue(types.TypeText))
- least := types.TupleValue(types.Uint64Value(1), types.TextValue("abc"))
- medium := types.TupleValue(types.Uint64Value(1), types.TextValue("def"))
- largest := types.TupleValue(types.Uint64Value(2), types.TextValue("abc"))
+ withNull := value.TupleValue(value.Uint64Value(1), value.NullValue(types.Text))
+ least := value.TupleValue(value.Uint64Value(1), value.TextValue("abc"))
+ medium := value.TupleValue(value.Uint64Value(1), value.TextValue("def"))
+ largest := value.TupleValue(value.Uint64Value(2), value.TextValue("abc"))
c, err := Compare(least, medium)
requireNoError(t, err)
@@ -280,9 +280,9 @@ func TestTuple(t *testing.T) {
}
func TestList(t *testing.T) {
- least := types.ListValue(types.Uint64Value(1), types.Uint64Value(1))
- medium := types.ListValue(types.Uint64Value(1), types.Uint64Value(2))
- largest := types.ListValue(types.Uint64Value(2), types.Uint64Value(1))
+ least := value.ListValue(value.Uint64Value(1), value.Uint64Value(1))
+ medium := value.ListValue(value.Uint64Value(1), value.Uint64Value(2))
+ largest := value.ListValue(value.Uint64Value(2), value.Uint64Value(1))
c, err := Compare(least, medium)
requireNoError(t, err)
@@ -298,8 +298,8 @@ func TestList(t *testing.T) {
}
func TestDyNumber(t *testing.T) {
- l := types.DyNumberValue("2")
- r := types.DyNumberValue("12")
+ l := value.DyNumberValue("2")
+ r := value.DyNumberValue("12")
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -314,9 +314,9 @@ func TestDyNumber(t *testing.T) {
}
func TestUUID(t *testing.T) {
- l := types.UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})
- r := types.UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17})
- g := types.UUIDValue([16]byte{100, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17})
+ l := value.UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})
+ r := value.UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17})
+ g := value.UUIDValue([16]byte{100, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17})
c, err := Compare(l, r)
requireNoError(t, err)
requireEqualValues(t, -1, c)
@@ -335,8 +335,8 @@ func TestUUID(t *testing.T) {
}
func TestIncompatiblePrimitives(t *testing.T) {
- l := types.Uint64Value(1)
- r := types.TimestampValue(2)
+ l := value.Uint64Value(1)
+ r := value.TimestampValue(2)
_, err := Compare(l, r)
if err == nil {
t.Errorf("WithStackTrace expected")
@@ -347,8 +347,8 @@ func TestIncompatiblePrimitives(t *testing.T) {
}
func TestIncompatibleTuples(t *testing.T) {
- l := types.TupleValue(types.Uint64Value(1), types.TextValue("abc"))
- r := types.TupleValue(types.Uint64Value(1), types.BytesValue([]byte("abc")))
+ l := value.TupleValue(value.Uint64Value(1), value.TextValue("abc"))
+ r := value.TupleValue(value.Uint64Value(1), value.BytesValue([]byte("abc")))
_, err := Compare(l, r)
if err == nil {
t.Error("WithStackTrace expected")
@@ -358,8 +358,8 @@ func TestIncompatibleTuples(t *testing.T) {
}
func TestTupleOfDifferentLength(t *testing.T) {
- l := types.TupleValue(types.Uint64Value(1), types.TextValue("abc"))
- r := types.TupleValue(types.Uint64Value(1), types.TextValue("abc"), types.TextValue("def"))
+ l := value.TupleValue(value.Uint64Value(1), value.TextValue("abc"))
+ r := value.TupleValue(value.Uint64Value(1), value.TextValue("abc"), value.TextValue("def"))
cmp, err := Compare(l, r)
requireNoError(t, err)
@@ -371,8 +371,8 @@ func TestTupleOfDifferentLength(t *testing.T) {
}
func TestTupleInTuple(t *testing.T) {
- l := types.TupleValue(types.Uint64Value(1), types.TupleValue(types.TextValue("abc"), types.BytesValue([]byte("xyz"))))
- r := types.TupleValue(types.Uint64Value(1), types.TupleValue(types.TextValue("def"), types.BytesValue([]byte("xyz"))))
+ l := value.TupleValue(value.Uint64Value(1), value.TupleValue(value.TextValue("abc"), value.BytesValue([]byte("xyz"))))
+ r := value.TupleValue(value.Uint64Value(1), value.TupleValue(value.TextValue("def"), value.BytesValue([]byte("xyz"))))
cmp, err := Compare(l, r)
requireNoError(t, err)
@@ -388,18 +388,18 @@ func TestTupleInTuple(t *testing.T) {
}
func TestListInList(t *testing.T) {
- l := types.ListValue(
- types.ListValue(
- types.TextValue("abc"), types.TextValue("def"),
- ), types.ListValue(
- types.TextValue("uvw"), types.TextValue("xyz"),
+ l := value.ListValue(
+ value.ListValue(
+ value.TextValue("abc"), value.TextValue("def"),
+ ), value.ListValue(
+ value.TextValue("uvw"), value.TextValue("xyz"),
),
)
- r := types.ListValue(
- types.ListValue(
- types.TextValue("abc"), types.TextValue("deg"),
- ), types.ListValue(
- types.TextValue("uvw"), types.TextValue("xyz"),
+ r := value.ListValue(
+ value.ListValue(
+ value.TextValue("abc"), value.TextValue("deg"),
+ ), value.ListValue(
+ value.TextValue("uvw"), value.TextValue("xyz"),
),
)
diff --git a/testutil/driver.go b/testutil/driver.go
index 6be8849e8..48b82d4ca 100644
--- a/testutil/driver.go
+++ b/testutil/driver.go
@@ -24,6 +24,7 @@ func (m MethodCode) String() string {
if method, ok := codeToString[m]; ok {
return method
}
+
return ""
}
@@ -33,6 +34,7 @@ func (m Method) Code() MethodCode {
if code, ok := grpcMethodToCode[m]; ok {
return code
}
+
return UnknownMethod
}
@@ -150,6 +152,7 @@ func (b *balancerStub) Invoke(
if b.onInvoke == nil {
return fmt.Errorf("database.onInvoke() not defined")
}
+
return b.onInvoke(ctx, method, args, reply, opts...)
}
@@ -162,6 +165,7 @@ func (b *balancerStub) NewStream(
if b.onNewStream == nil {
return nil, fmt.Errorf("database.onNewStream() not defined")
}
+
return b.onNewStream(ctx, desc, method, opts...)
}
@@ -170,6 +174,7 @@ func (b *balancerStub) Get(context.Context) (conn grpc.ClientConnInterface, err
onInvoke: b.onInvoke,
onNewStream: b.onNewStream,
}
+
return cc, nil
}
@@ -215,8 +220,10 @@ func WithInvokeHandlers(invokeHandlers InvokeHandlers) balancerOption {
Result: anyResult,
},
)
+
return nil
}
+
return fmt.Errorf("method '%s' not implemented", method)
}
}
@@ -233,6 +240,7 @@ func WithNewStreamHandlers(newStreamHandlers NewStreamHandlers) balancerOption {
if handler, ok := newStreamHandlers[Method(method).Code()]; ok {
return handler(desc)
}
+
return nil, fmt.Errorf("method '%s' not implemented", method)
}
}
@@ -245,6 +253,7 @@ func NewBalancer(opts ...balancerOption) *balancerStub {
opt(c)
}
}
+
return c
}
@@ -272,6 +281,7 @@ func (c *clientConn) Address() string {
if c.onAddress != nil {
return c.onAddress()
}
+
return ""
}
@@ -285,6 +295,7 @@ func (c *clientConn) Invoke(
if c.onInvoke == nil {
return fmt.Errorf("onInvoke not implemented (method: %s, request: %v, response: %v)", method, args, reply)
}
+
return c.onInvoke(ctx, method, args, reply, opts...)
}
@@ -297,6 +308,7 @@ func (c *clientConn) NewStream(
if c.onNewStream == nil {
return nil, fmt.Errorf("onNewStream not implemented (method: %s, desc: %v)", method, desc)
}
+
return c.onNewStream(ctx, desc, method, opts...)
}
@@ -313,6 +325,7 @@ func (s *ClientStream) Header() (metadata.MD, error) {
if s.OnHeader == nil {
return nil, xerrors.WithStackTrace(ErrNotImplemented)
}
+
return s.OnHeader()
}
@@ -320,6 +333,7 @@ func (s *ClientStream) Trailer() metadata.MD {
if s.OnTrailer == nil {
return nil
}
+
return s.OnTrailer()
}
@@ -327,6 +341,7 @@ func (s *ClientStream) CloseSend() error {
if s.OnCloseSend == nil {
return xerrors.WithStackTrace(ErrNotImplemented)
}
+
return s.OnCloseSend()
}
@@ -334,6 +349,7 @@ func (s *ClientStream) Context() context.Context {
if s.OnContext == nil {
return nil
}
+
return s.OnContext()
}
@@ -341,6 +357,7 @@ func (s *ClientStream) SendMsg(m interface{}) error {
if s.OnSendMsg == nil {
return xerrors.WithStackTrace(ErrNotImplemented)
}
+
return s.OnSendMsg(m)
}
@@ -348,10 +365,12 @@ func (s *ClientStream) RecvMsg(m interface{}) error {
if s.OnRecvMsg == nil {
return xerrors.WithStackTrace(ErrNotImplemented)
}
+
return s.OnRecvMsg(m)
}
func lastSegment(m string) string {
s := strings.Split(m, "/")
+
return s[len(s)-1]
}
diff --git a/testutil/file_line.go b/testutil/file_line.go
index 37be268b5..5bc37c4f5 100644
--- a/testutil/file_line.go
+++ b/testutil/file_line.go
@@ -8,5 +8,6 @@ import (
func FileLine(skip int) string {
_, file, line, _ := runtime.Caller(skip)
+
return filepath.Base(file) + ":" + strconv.Itoa(line)
}
diff --git a/testutil/session.go b/testutil/session.go
index cdc1c5338..d5ca81899 100644
--- a/testutil/session.go
+++ b/testutil/session.go
@@ -35,10 +35,11 @@ func SessionID(opts ...sessionIDOption) string {
nodeID: uint32(xrand.New().Int64(math.MaxUint32)),
hash: strconv.FormatInt(xrand.New().Int64(math.MaxInt64), 16),
}
- for _, o := range opts {
- if o != nil {
- o(h)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(h)
}
}
+
return fmt.Sprintf("ydb://session/%d?node_id=%d&id=%s==", h.serviceID, h.nodeID, h.hash)
}
diff --git a/topic/example_test.go b/topic/example_test.go
index bba68c4be..9df1fab42 100644
--- a/topic/example_test.go
+++ b/topic/example_test.go
@@ -21,6 +21,7 @@ func Example_createTopic() {
db, err := ydb.Open(ctx, connectionString)
if err != nil {
log.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -35,6 +36,7 @@ func Example_createTopic() {
)
if err != nil {
log.Printf("failed create topic: %v", err)
+
return
}
}
@@ -48,6 +50,7 @@ func Example_alterTopic() {
db, err := ydb.Open(ctx, connectionString)
if err != nil {
log.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -60,6 +63,7 @@ func Example_alterTopic() {
)
if err != nil {
log.Printf("failed alter topic: %v", err)
+
return
}
}
@@ -73,6 +77,7 @@ func Example_describeTopic() {
db, err := ydb.Open(ctx, connectionString)
if err != nil {
log.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -80,6 +85,7 @@ func Example_describeTopic() {
descResult, err := db.Topic().Describe(ctx, "topic-path")
if err != nil {
log.Printf("failed drop topic: %v", err)
+
return
}
fmt.Printf("describe: %#v\n", descResult)
@@ -94,6 +100,7 @@ func Example_dropTopic() {
db, err := ydb.Open(ctx, connectionString)
if err != nil {
log.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -101,6 +108,7 @@ func Example_dropTopic() {
err = db.Topic().Drop(ctx, "topic-path")
if err != nil {
log.Printf("failed drop topic: %v", err)
+
return
}
}
@@ -114,6 +122,7 @@ func Example_readMessage() {
db, err := ydb.Open(ctx, connectionString)
if err != nil {
log.Printf("failed connect: %v", err)
+
return
}
defer db.Close(ctx) // cleanup resources
@@ -121,6 +130,7 @@ func Example_readMessage() {
reader, err := db.Topic().StartReader("consumer", topicoptions.ReadTopic("/topic/path"))
if err != nil {
fmt.Printf("failed start reader: %v", err)
+
return
}
@@ -128,12 +138,14 @@ func Example_readMessage() {
mess, err := reader.ReadMessage(ctx)
if err != nil {
fmt.Printf("failed start reader: %v", err)
+
return
}
content, err := io.ReadAll(mess)
if err != nil {
fmt.Printf("failed start reader: %v", err)
+
return
}
fmt.Println(string(content))
diff --git a/topic/topicoptions/topicoptions_alter.go b/topic/topicoptions/topicoptions_alter.go
index 3667e0efa..52700a7f4 100644
--- a/topic/topicoptions/topicoptions_alter.go
+++ b/topic/topicoptions/topicoptions_alter.go
@@ -43,6 +43,7 @@ func AlterWithSupportedCodecs(codecs ...topictypes.Codec) AlterOption {
sort.Slice(codecs, func(i, j int) bool {
return codecs[i] < codecs[j]
})
+
return withSupportedCodecs(codecs)
}
@@ -66,12 +67,14 @@ func AlterWithAddConsumers(consumers ...topictypes.Consumer) AlterOption {
sort.Slice(consumers, func(i, j int) bool {
return consumers[i].Name < consumers[j].Name
})
+
return withAddConsumers(consumers)
}
// AlterWithDropConsumers drop consumer from the topic
func AlterWithDropConsumers(consumersName ...string) AlterOption {
sort.Strings(consumersName)
+
return withDropConsumers(consumersName)
}
@@ -96,6 +99,7 @@ func AlterConsumerWithSupportedCodecs(name string, codecs []topictypes.Codec) Al
sort.Slice(codecs, func(i, j int) bool {
return codecs[i] < codecs[j]
})
+
return withConsumerWithSupportedCodecs{
name: name,
codecs: codecs,
@@ -123,5 +127,6 @@ func ensureAlterConsumer(
}
}
consumers = append(consumers, rawtopic.AlterConsumer{Name: name})
+
return consumers, len(consumers) - 1
}
diff --git a/topic/topicoptions/topicoptions_create.go b/topic/topicoptions/topicoptions_create.go
index cf111234f..6fa1cb4dc 100644
--- a/topic/topicoptions/topicoptions_create.go
+++ b/topic/topicoptions/topicoptions_create.go
@@ -43,6 +43,7 @@ func CreateWithSupportedCodecs(codecs ...topictypes.Codec) CreateOption {
sort.Slice(codecs, func(i, j int) bool {
return codecs[i] < codecs[j]
})
+
return withSupportedCodecs(codecs)
}
@@ -66,5 +67,6 @@ func CreateWithConsumer(consumers ...topictypes.Consumer) CreateOption {
sort.Slice(consumers, func(i, j int) bool {
return consumers[i].Name < consumers[j].Name
})
+
return withAddConsumers(consumers)
}
diff --git a/topic/topicreader/batch_options.go b/topic/topicreader/batch_options.go
index b4c670c31..166432535 100644
--- a/topic/topicreader/batch_options.go
+++ b/topic/topicreader/batch_options.go
@@ -12,6 +12,7 @@ func (count WithBatchMaxCount) Apply(
options topicreaderinternal.ReadMessageBatchOptions,
) topicreaderinternal.ReadMessageBatchOptions {
options.MaxCount = int(count)
+
return options
}
@@ -33,5 +34,6 @@ func (count WithBatchPreferMinCount) Apply(
panic("ydb: min batch size must be 1 or greater")
}
options.MinCount = int(count)
+
return options
}
diff --git a/topic/topicreader/errors.go b/topic/topicreader/errors.go
index 199a68257..f5f4db2d0 100644
--- a/topic/topicreader/errors.go
+++ b/topic/topicreader/errors.go
@@ -9,7 +9,7 @@ import (
// ErrUnexpectedCodec will return if topicreader receive message with unknown codec.
// client side must check error with errors.Is
-var ErrUnexpectedCodec = topicreaderinternal.PublicErrUnexpectedCodec
+var ErrUnexpectedCodec = topicreaderinternal.ErrPublicUnexpectedCodec
// ErrConcurrencyCall return if method on reader called in concurrency
// client side must check error with errors.Is
diff --git a/topic/topicreader/reader.go b/topic/topicreader/reader.go
index cd6831f7e..9c50d4a51 100644
--- a/topic/topicreader/reader.go
+++ b/topic/topicreader/reader.go
@@ -2,9 +2,9 @@ package topicreader
import (
"context"
+ "sync/atomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/topic/topicreaderinternal"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
@@ -21,8 +21,8 @@ import (
// | Close | - | - | - | - |
type Reader struct {
reader topicreaderinternal.Reader
- readInFlyght xatomic.Bool
- commitInFlyght xatomic.Bool
+ readInFlyght atomic.Bool
+ commitInFlyght atomic.Bool
}
// NewReader
@@ -124,7 +124,7 @@ func (r *Reader) Close(ctx context.Context) error {
return r.reader.Close(ctx)
}
-func (r *Reader) inCall(inFlight *xatomic.Bool) error {
+func (r *Reader) inCall(inFlight *atomic.Bool) error {
if inFlight.CompareAndSwap(false, true) {
return nil
}
@@ -132,7 +132,7 @@ func (r *Reader) inCall(inFlight *xatomic.Bool) error {
return xerrors.WithStackTrace(ErrConcurrencyCall)
}
-func (r *Reader) outCall(inFlight *xatomic.Bool) {
+func (r *Reader) outCall(inFlight *atomic.Bool) {
if inFlight.CompareAndSwap(true, false) {
return
}
diff --git a/topic/topicwriter/topicwriter.go b/topic/topicwriter/topicwriter.go
index 341e16da4..a9b5971f3 100644
--- a/topic/topicwriter/topicwriter.go
+++ b/topic/topicwriter/topicwriter.go
@@ -50,6 +50,7 @@ func (w *Writer) WaitInit(ctx context.Context) (err error) {
if err != nil {
return err
}
+
return nil
}
@@ -61,6 +62,7 @@ func (w *Writer) WaitInitInfo(ctx context.Context) (info PublicInitialInfo, err
return PublicInitialInfo{}, err
}
publicInfo := PublicInitialInfo{LastSeqNum: privateInfo.LastSeqNum}
+
return publicInfo, nil
}
diff --git a/trace/details.go b/trace/details.go
index c1617aa2d..124885135 100644
--- a/trace/details.go
+++ b/trace/details.go
@@ -24,6 +24,7 @@ func (d Details) String() string {
}
}
sort.Strings(ss)
+
return strings.Join(ss, "|")
}
@@ -43,6 +44,11 @@ const (
TablePoolSessionLifeCycleEvents
TablePoolAPIEvents
+ QuerySessionEvents
+ QueryResultEvents
+ QueryTransactionEvents
+ QueryPoolEvents
+
TopicControlPlaneEvents
TopicReaderCustomerEvents
@@ -72,9 +78,6 @@ const (
CoordinationEvents
- // Deprecated: has no effect now
- DriverClusterEvents
-
DriverEvents = DriverConnEvents |
DriverBalancerEvents |
DriverResolverEvents |
@@ -89,6 +92,11 @@ const (
TablePoolSessionLifeCycleEvents |
TablePoolAPIEvents
+ QueryEvents = QuerySessionEvents |
+ QueryPoolEvents |
+ QueryResultEvents |
+ QueryTransactionEvents
+
TablePoolEvents = TablePoolLifeCycleEvents |
TablePoolSessionLifeCycleEvents |
TablePoolAPIEvents
@@ -143,6 +151,12 @@ var (
TablePoolSessionLifeCycleEvents: "ydb.table.pool.session",
TablePoolAPIEvents: "ydb.table.pool.api",
+ QueryEvents: "ydb.query",
+ QueryPoolEvents: "ydb.query.pool",
+ QuerySessionEvents: "ydb.query.session",
+ QueryResultEvents: "ydb.query.result",
+ QueryTransactionEvents: "ydb.query.tx",
+
DatabaseSQLEvents: "ydb.database.sql",
DatabaseSQLConnectorEvents: "ydb.database.sql.connector",
DatabaseSQLConnEvents: "ydb.database.sql.conn",
@@ -190,9 +204,9 @@ func MatchDetails(pattern string, opts ...matchDetailsOption) (d Details) {
err error
)
- for _, o := range opts {
- if o != nil {
- o(h)
+ for _, opt := range opts {
+ if opt != nil {
+ opt(h)
}
}
if h.posixMatch {
@@ -211,5 +225,6 @@ func MatchDetails(pattern string, opts ...matchDetailsOption) (d Details) {
if d == 0 {
return h.defaultDetails
}
+
return d
}
diff --git a/trace/details_test.go b/trace/details_test.go
index 1202daaf4..362090f68 100644
--- a/trace/details_test.go
+++ b/trace/details_test.go
@@ -35,6 +35,10 @@ func TestDetailsMatch(t *testing.T) {
pattern: `^ydb\.table`,
details: TableEvents,
},
+ {
+ pattern: `^ydb\.query`,
+ details: QueryEvents,
+ },
{
pattern: `^ydb\.scripting$`,
details: ScriptingEvents,
@@ -63,6 +67,10 @@ func TestDetailsMatch(t *testing.T) {
pattern: `^ydb\.table\.(pool\.(session|api)|session).*$`,
details: TablePoolSessionLifeCycleEvents | TablePoolAPIEvents | TableSessionEvents,
},
+ {
+ pattern: `^ydb\.query\.(pool|session|tx|result).*$`,
+ details: QueryPoolEvents | QuerySessionEvents | QueryTransactionEvents | QueryResultEvents,
+ },
{
pattern: `^ydb\.((database.sql.tx)|driver.(balancer|conn)|(table\.pool)|retry)$`,
details: DriverBalancerEvents | DriverConnEvents | TablePoolLifeCycleEvents | DatabaseSQLTxEvents | RetryEvents,
diff --git a/trace/driver.go b/trace/driver.go
index 5c31cfbd5..e33dac555 100644
--- a/trace/driver.go
+++ b/trace/driver.go
@@ -24,35 +24,21 @@ type (
OnPoolNew func(DriverConnPoolNewStartInfo) func(DriverConnPoolNewDoneInfo)
OnPoolRelease func(DriverConnPoolReleaseStartInfo) func(DriverConnPoolReleaseDoneInfo)
- // Deprecated: driver not notificate about this event
- OnNetRead func(DriverNetReadStartInfo) func(DriverNetReadDoneInfo)
- // Deprecated: driver not notificate about this event
- OnNetWrite func(DriverNetWriteStartInfo) func(DriverNetWriteDoneInfo)
- // Deprecated: driver not notificate about this event
- OnNetDial func(DriverNetDialStartInfo) func(DriverNetDialDoneInfo)
- // Deprecated: driver not notificate about this event
- OnNetClose func(DriverNetCloseStartInfo) func(DriverNetCloseDoneInfo)
-
// Resolver events
OnResolve func(DriverResolveStartInfo) func(DriverResolveDoneInfo)
// Conn events
- OnConnStateChange func(DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo)
- OnConnInvoke func(DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo)
- OnConnNewStream func(
- DriverConnNewStreamStartInfo,
- ) func(
- DriverConnNewStreamRecvInfo,
- ) func(
- DriverConnNewStreamDoneInfo,
- )
- // Deprecated: driver not notificate about this event
- OnConnTake func(DriverConnTakeStartInfo) func(DriverConnTakeDoneInfo)
- OnConnDial func(DriverConnDialStartInfo) func(DriverConnDialDoneInfo)
- OnConnPark func(DriverConnParkStartInfo) func(DriverConnParkDoneInfo)
- OnConnBan func(DriverConnBanStartInfo) func(DriverConnBanDoneInfo)
- OnConnAllow func(DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo)
- OnConnClose func(DriverConnCloseStartInfo) func(DriverConnCloseDoneInfo)
+ OnConnStateChange func(DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo)
+ OnConnInvoke func(DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo)
+ OnConnNewStream func(DriverConnNewStreamStartInfo) func(DriverConnNewStreamDoneInfo)
+ OnConnStreamRecvMsg func(DriverConnStreamRecvMsgStartInfo) func(DriverConnStreamRecvMsgDoneInfo)
+ OnConnStreamSendMsg func(DriverConnStreamSendMsgStartInfo) func(DriverConnStreamSendMsgDoneInfo)
+ OnConnStreamCloseSend func(DriverConnStreamCloseSendStartInfo) func(DriverConnStreamCloseSendDoneInfo)
+ OnConnDial func(DriverConnDialStartInfo) func(DriverConnDialDoneInfo)
+ OnConnBan func(DriverConnBanStartInfo) func(DriverConnBanDoneInfo)
+ OnConnAllow func(DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo)
+ OnConnPark func(DriverConnParkStartInfo) func(DriverConnParkDoneInfo)
+ OnConnClose func(DriverConnCloseStartInfo) func(DriverConnCloseDoneInfo)
// Repeater events
OnRepeaterWakeUp func(DriverRepeaterWakeUpStartInfo) func(DriverRepeaterWakeUpDoneInfo)
@@ -60,12 +46,6 @@ type (
// Balancer events
OnBalancerInit func(DriverBalancerInitStartInfo) func(DriverBalancerInitDoneInfo)
- // Deprecated: driver not notificate about this event
- OnBalancerDialEntrypoint func(
- DriverBalancerDialEntrypointStartInfo,
- ) func(
- DriverBalancerDialEntrypointDoneInfo,
- )
OnBalancerClose func(DriverBalancerCloseStartInfo) func(DriverBalancerCloseDoneInfo)
OnBalancerChooseEndpoint func(
DriverBalancerChooseEndpointStartInfo,
@@ -90,12 +70,14 @@ type Method string
// Name returns the rpc method name.
func (m Method) Name() (s string) {
_, s = m.Split()
+
return
}
// Service returns the rpc service name.
func (m Method) Service() (s string) {
s, _ = m.Split()
+
return
}
@@ -112,6 +94,7 @@ func (m Method) Split() (service, method string) {
if i == -1 {
return string(m), string(m)
}
+
return strings.TrimPrefix(string(m[:i]), "/"), string(m[i+1:])
}
@@ -169,8 +152,6 @@ type (
Added []EndpointInfo
Dropped []EndpointInfo
LocalDC string
- // Deprecated: this field always nil
- Error error
}
DriverBalancerClusterDiscoveryAttemptStartInfo struct {
// Context make available context in trace callback function.
@@ -323,13 +304,42 @@ type (
Endpoint EndpointInfo
Method Method
}
- DriverConnNewStreamRecvInfo struct {
+ DriverConnNewStreamDoneInfo struct {
Error error
+ State ConnState
}
- DriverConnNewStreamDoneInfo struct {
- Error error
- State ConnState
- Metadata map[string][]string
+ DriverConnStreamRecvMsgStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ DriverConnStreamRecvMsgDoneInfo struct {
+ Error error
+ }
+ DriverConnStreamSendMsgStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ DriverConnStreamSendMsgDoneInfo struct {
+ Error error
+ }
+ DriverConnStreamCloseSendStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ DriverConnStreamCloseSendDoneInfo struct {
+ Error error
}
DriverBalancerInitStartInfo struct {
// Context make available context in trace callback function.
diff --git a/trace/driver_gtrace.go b/trace/driver_gtrace.go
index 0fe4e4fe7..4e737f5db 100644
--- a/trace/driver_gtrace.go
+++ b/trace/driver_gtrace.go
@@ -206,44 +206,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnNetRead
- h2 := x.OnNetRead
- ret.OnNetRead = func(d DriverNetReadStartInfo) func(DriverNetReadDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- var r, r1 func(DriverNetReadDoneInfo)
- if h1 != nil {
- r = h1(d)
- }
- if h2 != nil {
- r1 = h2(d)
- }
- return func(d DriverNetReadDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r != nil {
- r(d)
- }
- if r1 != nil {
- r1(d)
- }
- }
- }
- }
- {
- h1 := t.OnNetWrite
- h2 := x.OnNetWrite
- ret.OnNetWrite = func(d DriverNetWriteStartInfo) func(DriverNetWriteDoneInfo) {
+ h1 := t.OnResolve
+ h2 := x.OnResolve
+ ret.OnResolve = func(d DriverResolveStartInfo) func(DriverResolveDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -251,14 +216,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverNetWriteDoneInfo)
+ var r, r1 func(DriverResolveDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverNetWriteDoneInfo) {
+ return func(d DriverResolveDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -276,9 +241,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnNetDial
- h2 := x.OnNetDial
- ret.OnNetDial = func(d DriverNetDialStartInfo) func(DriverNetDialDoneInfo) {
+ h1 := t.OnConnStateChange
+ h2 := x.OnConnStateChange
+ ret.OnConnStateChange = func(d DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -286,14 +251,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverNetDialDoneInfo)
+ var r, r1 func(DriverConnStateChangeDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverNetDialDoneInfo) {
+ return func(d DriverConnStateChangeDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -311,9 +276,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnNetClose
- h2 := x.OnNetClose
- ret.OnNetClose = func(d DriverNetCloseStartInfo) func(DriverNetCloseDoneInfo) {
+ h1 := t.OnConnInvoke
+ h2 := x.OnConnInvoke
+ ret.OnConnInvoke = func(d DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -321,14 +286,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverNetCloseDoneInfo)
+ var r, r1 func(DriverConnInvokeDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverNetCloseDoneInfo) {
+ return func(d DriverConnInvokeDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -346,9 +311,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnResolve
- h2 := x.OnResolve
- ret.OnResolve = func(d DriverResolveStartInfo) func(DriverResolveDoneInfo) {
+ h1 := t.OnConnNewStream
+ h2 := x.OnConnNewStream
+ ret.OnConnNewStream = func(d DriverConnNewStreamStartInfo) func(DriverConnNewStreamDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -356,14 +321,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverResolveDoneInfo)
+ var r, r1 func(DriverConnNewStreamDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverResolveDoneInfo) {
+ return func(d DriverConnNewStreamDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -381,9 +346,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnConnStateChange
- h2 := x.OnConnStateChange
- ret.OnConnStateChange = func(d DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo) {
+ h1 := t.OnConnStreamRecvMsg
+ h2 := x.OnConnStreamRecvMsg
+ ret.OnConnStreamRecvMsg = func(d DriverConnStreamRecvMsgStartInfo) func(DriverConnStreamRecvMsgDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -391,14 +356,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverConnStateChangeDoneInfo)
+ var r, r1 func(DriverConnStreamRecvMsgDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverConnStateChangeDoneInfo) {
+ return func(d DriverConnStreamRecvMsgDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -416,9 +381,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnConnInvoke
- h2 := x.OnConnInvoke
- ret.OnConnInvoke = func(d DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo) {
+ h1 := t.OnConnStreamSendMsg
+ h2 := x.OnConnStreamSendMsg
+ ret.OnConnStreamSendMsg = func(d DriverConnStreamSendMsgStartInfo) func(DriverConnStreamSendMsgDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -426,14 +391,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverConnInvokeDoneInfo)
+ var r, r1 func(DriverConnStreamSendMsgDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverConnInvokeDoneInfo) {
+ return func(d DriverConnStreamSendMsgDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -451,60 +416,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnConnNewStream
- h2 := x.OnConnNewStream
- ret.OnConnNewStream = func(d DriverConnNewStreamStartInfo) func(DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- var r, r1 func(DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo)
- if h1 != nil {
- r = h1(d)
- }
- if h2 != nil {
- r1 = h2(d)
- }
- return func(d DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- var r2, r3 func(DriverConnNewStreamDoneInfo)
- if r != nil {
- r2 = r(d)
- }
- if r1 != nil {
- r3 = r1(d)
- }
- return func(d DriverConnNewStreamDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(d)
- }
- if r3 != nil {
- r3(d)
- }
- }
- }
- }
- }
- {
- h1 := t.OnConnTake
- h2 := x.OnConnTake
- ret.OnConnTake = func(d DriverConnTakeStartInfo) func(DriverConnTakeDoneInfo) {
+ h1 := t.OnConnStreamCloseSend
+ h2 := x.OnConnStreamCloseSend
+ ret.OnConnStreamCloseSend = func(d DriverConnStreamCloseSendStartInfo) func(DriverConnStreamCloseSendDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -512,14 +426,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverConnTakeDoneInfo)
+ var r, r1 func(DriverConnStreamCloseSendDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverConnTakeDoneInfo) {
+ return func(d DriverConnStreamCloseSendDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -572,9 +486,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnConnPark
- h2 := x.OnConnPark
- ret.OnConnPark = func(d DriverConnParkStartInfo) func(DriverConnParkDoneInfo) {
+ h1 := t.OnConnBan
+ h2 := x.OnConnBan
+ ret.OnConnBan = func(d DriverConnBanStartInfo) func(DriverConnBanDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -582,14 +496,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverConnParkDoneInfo)
+ var r, r1 func(DriverConnBanDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverConnParkDoneInfo) {
+ return func(d DriverConnBanDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -607,9 +521,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnConnBan
- h2 := x.OnConnBan
- ret.OnConnBan = func(d DriverConnBanStartInfo) func(DriverConnBanDoneInfo) {
+ h1 := t.OnConnAllow
+ h2 := x.OnConnAllow
+ ret.OnConnAllow = func(d DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -617,14 +531,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverConnBanDoneInfo)
+ var r, r1 func(DriverConnAllowDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverConnBanDoneInfo) {
+ return func(d DriverConnAllowDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -642,9 +556,9 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
{
- h1 := t.OnConnAllow
- h2 := x.OnConnAllow
- ret.OnConnAllow = func(d DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo) {
+ h1 := t.OnConnPark
+ h2 := x.OnConnPark
+ ret.OnConnPark = func(d DriverConnParkStartInfo) func(DriverConnParkDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -652,14 +566,14 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}()
}
- var r, r1 func(DriverConnAllowDoneInfo)
+ var r, r1 func(DriverConnParkDoneInfo)
if h1 != nil {
r = h1(d)
}
if h2 != nil {
r1 = h2(d)
}
- return func(d DriverConnAllowDoneInfo) {
+ return func(d DriverConnParkDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -781,41 +695,6 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
}
- {
- h1 := t.OnBalancerDialEntrypoint
- h2 := x.OnBalancerDialEntrypoint
- ret.OnBalancerDialEntrypoint = func(d DriverBalancerDialEntrypointStartInfo) func(DriverBalancerDialEntrypointDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- var r, r1 func(DriverBalancerDialEntrypointDoneInfo)
- if h1 != nil {
- r = h1(d)
- }
- if h2 != nil {
- r1 = h2(d)
- }
- return func(d DriverBalancerDialEntrypointDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r != nil {
- r(d)
- }
- if r1 != nil {
- r1(d)
- }
- }
- }
- }
{
h1 := t.OnBalancerClose
h2 := x.OnBalancerClose
@@ -1068,148 +947,106 @@ func (t *Driver) onPoolRelease(d DriverConnPoolReleaseStartInfo) func(DriverConn
}
return res
}
-func (t *Driver) onNetRead(d DriverNetReadStartInfo) func(DriverNetReadDoneInfo) {
- fn := t.OnNetRead
- if fn == nil {
- return func(DriverNetReadDoneInfo) {
- return
- }
- }
- res := fn(d)
- if res == nil {
- return func(DriverNetReadDoneInfo) {
- return
- }
- }
- return res
-}
-func (t *Driver) onNetWrite(d DriverNetWriteStartInfo) func(DriverNetWriteDoneInfo) {
- fn := t.OnNetWrite
+func (t *Driver) onResolve(d DriverResolveStartInfo) func(DriverResolveDoneInfo) {
+ fn := t.OnResolve
if fn == nil {
- return func(DriverNetWriteDoneInfo) {
+ return func(DriverResolveDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverNetWriteDoneInfo) {
+ return func(DriverResolveDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onNetDial(d DriverNetDialStartInfo) func(DriverNetDialDoneInfo) {
- fn := t.OnNetDial
+func (t *Driver) onConnStateChange(d DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo) {
+ fn := t.OnConnStateChange
if fn == nil {
- return func(DriverNetDialDoneInfo) {
+ return func(DriverConnStateChangeDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverNetDialDoneInfo) {
+ return func(DriverConnStateChangeDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onNetClose(d DriverNetCloseStartInfo) func(DriverNetCloseDoneInfo) {
- fn := t.OnNetClose
+func (t *Driver) onConnInvoke(d DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo) {
+ fn := t.OnConnInvoke
if fn == nil {
- return func(DriverNetCloseDoneInfo) {
+ return func(DriverConnInvokeDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverNetCloseDoneInfo) {
+ return func(DriverConnInvokeDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onResolve(d DriverResolveStartInfo) func(DriverResolveDoneInfo) {
- fn := t.OnResolve
+func (t *Driver) onConnNewStream(d DriverConnNewStreamStartInfo) func(DriverConnNewStreamDoneInfo) {
+ fn := t.OnConnNewStream
if fn == nil {
- return func(DriverResolveDoneInfo) {
+ return func(DriverConnNewStreamDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverResolveDoneInfo) {
+ return func(DriverConnNewStreamDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onConnStateChange(d DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo) {
- fn := t.OnConnStateChange
+func (t *Driver) onConnStreamRecvMsg(d DriverConnStreamRecvMsgStartInfo) func(DriverConnStreamRecvMsgDoneInfo) {
+ fn := t.OnConnStreamRecvMsg
if fn == nil {
- return func(DriverConnStateChangeDoneInfo) {
+ return func(DriverConnStreamRecvMsgDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverConnStateChangeDoneInfo) {
+ return func(DriverConnStreamRecvMsgDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onConnInvoke(d DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo) {
- fn := t.OnConnInvoke
+func (t *Driver) onConnStreamSendMsg(d DriverConnStreamSendMsgStartInfo) func(DriverConnStreamSendMsgDoneInfo) {
+ fn := t.OnConnStreamSendMsg
if fn == nil {
- return func(DriverConnInvokeDoneInfo) {
+ return func(DriverConnStreamSendMsgDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverConnInvokeDoneInfo) {
+ return func(DriverConnStreamSendMsgDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onConnNewStream(d DriverConnNewStreamStartInfo) func(DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo) {
- fn := t.OnConnNewStream
- if fn == nil {
- return func(DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo) {
- return func(DriverConnNewStreamDoneInfo) {
- return
- }
- }
- }
- res := fn(d)
- if res == nil {
- return func(DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo) {
- return func(DriverConnNewStreamDoneInfo) {
- return
- }
- }
- }
- return func(d DriverConnNewStreamRecvInfo) func(DriverConnNewStreamDoneInfo) {
- res := res(d)
- if res == nil {
- return func(DriverConnNewStreamDoneInfo) {
- return
- }
- }
- return res
- }
-}
-func (t *Driver) onConnTake(d DriverConnTakeStartInfo) func(DriverConnTakeDoneInfo) {
- fn := t.OnConnTake
+func (t *Driver) onConnStreamCloseSend(d DriverConnStreamCloseSendStartInfo) func(DriverConnStreamCloseSendDoneInfo) {
+ fn := t.OnConnStreamCloseSend
if fn == nil {
- return func(DriverConnTakeDoneInfo) {
+ return func(DriverConnStreamCloseSendDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverConnTakeDoneInfo) {
+ return func(DriverConnStreamCloseSendDoneInfo) {
return
}
}
@@ -1230,46 +1067,46 @@ func (t *Driver) onConnDial(d DriverConnDialStartInfo) func(DriverConnDialDoneIn
}
return res
}
-func (t *Driver) onConnPark(d DriverConnParkStartInfo) func(DriverConnParkDoneInfo) {
- fn := t.OnConnPark
+func (t *Driver) onConnBan(d DriverConnBanStartInfo) func(DriverConnBanDoneInfo) {
+ fn := t.OnConnBan
if fn == nil {
- return func(DriverConnParkDoneInfo) {
+ return func(DriverConnBanDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverConnParkDoneInfo) {
+ return func(DriverConnBanDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onConnBan(d DriverConnBanStartInfo) func(DriverConnBanDoneInfo) {
- fn := t.OnConnBan
+func (t *Driver) onConnAllow(d DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo) {
+ fn := t.OnConnAllow
if fn == nil {
- return func(DriverConnBanDoneInfo) {
+ return func(DriverConnAllowDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverConnBanDoneInfo) {
+ return func(DriverConnAllowDoneInfo) {
return
}
}
return res
}
-func (t *Driver) onConnAllow(d DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo) {
- fn := t.OnConnAllow
+func (t *Driver) onConnPark(d DriverConnParkStartInfo) func(DriverConnParkDoneInfo) {
+ fn := t.OnConnPark
if fn == nil {
- return func(DriverConnAllowDoneInfo) {
+ return func(DriverConnParkDoneInfo) {
return
}
}
res := fn(d)
if res == nil {
- return func(DriverConnAllowDoneInfo) {
+ return func(DriverConnParkDoneInfo) {
return
}
}
@@ -1320,21 +1157,6 @@ func (t *Driver) onBalancerInit(d DriverBalancerInitStartInfo) func(DriverBalanc
}
return res
}
-func (t *Driver) onBalancerDialEntrypoint(d DriverBalancerDialEntrypointStartInfo) func(DriverBalancerDialEntrypointDoneInfo) {
- fn := t.OnBalancerDialEntrypoint
- if fn == nil {
- return func(DriverBalancerDialEntrypointDoneInfo) {
- return
- }
- }
- res := fn(d)
- if res == nil {
- return func(DriverBalancerDialEntrypointDoneInfo) {
- return
- }
- }
- return res
-}
func (t *Driver) onBalancerClose(d DriverBalancerCloseStartInfo) func(DriverBalancerCloseDoneInfo) {
fn := t.OnBalancerClose
if fn == nil {
@@ -1470,55 +1292,6 @@ func DriverOnPoolRelease(t *Driver, c *context.Context, call call) func(error) {
res(p)
}
}
-func DriverOnNetRead(t *Driver, call call, address string, buffer int) func(received int, _ error) {
- var p DriverNetReadStartInfo
- p.Call = call
- p.Address = address
- p.Buffer = buffer
- res := t.onNetRead(p)
- return func(received int, e error) {
- var p DriverNetReadDoneInfo
- p.Received = received
- p.Error = e
- res(p)
- }
-}
-func DriverOnNetWrite(t *Driver, call call, address string, bytes int) func(sent int, _ error) {
- var p DriverNetWriteStartInfo
- p.Call = call
- p.Address = address
- p.Bytes = bytes
- res := t.onNetWrite(p)
- return func(sent int, e error) {
- var p DriverNetWriteDoneInfo
- p.Sent = sent
- p.Error = e
- res(p)
- }
-}
-func DriverOnNetDial(t *Driver, c *context.Context, call call, address string) func(error) {
- var p DriverNetDialStartInfo
- p.Context = c
- p.Call = call
- p.Address = address
- res := t.onNetDial(p)
- return func(e error) {
- var p DriverNetDialDoneInfo
- p.Error = e
- res(p)
- }
-}
-func DriverOnNetClose(t *Driver, call call, address string) func(error) {
- var p DriverNetCloseStartInfo
- p.Call = call
- p.Address = address
- res := t.onNetClose(p)
- return func(e error) {
- var p DriverNetCloseDoneInfo
- p.Error = e
- res(p)
- }
-}
func DriverOnResolve(t *Driver, call call, target string, resolved []string) func(error) {
var p DriverResolveStartInfo
p.Call = call
@@ -1561,58 +1334,61 @@ func DriverOnConnInvoke(t *Driver, c *context.Context, call call, endpoint Endpo
res(p)
}
}
-func DriverOnConnNewStream(t *Driver, c *context.Context, call call, endpoint EndpointInfo, m Method) func(error) func(_ error, state ConnState, metadata map[string][]string) {
+func DriverOnConnNewStream(t *Driver, c *context.Context, call call, endpoint EndpointInfo, m Method) func(_ error, state ConnState) {
var p DriverConnNewStreamStartInfo
p.Context = c
p.Call = call
p.Endpoint = endpoint
p.Method = m
res := t.onConnNewStream(p)
- return func(e error) func(error, ConnState, map[string][]string) {
- var p DriverConnNewStreamRecvInfo
+ return func(e error, state ConnState) {
+ var p DriverConnNewStreamDoneInfo
p.Error = e
- res := res(p)
- return func(e error, state ConnState, metadata map[string][]string) {
- var p DriverConnNewStreamDoneInfo
- p.Error = e
- p.State = state
- p.Metadata = metadata
- res(p)
- }
+ p.State = state
+ res(p)
}
}
-func DriverOnConnTake(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
- var p DriverConnTakeStartInfo
+func DriverOnConnStreamRecvMsg(t *Driver, c *context.Context, call call) func(error) {
+ var p DriverConnStreamRecvMsgStartInfo
p.Context = c
p.Call = call
- p.Endpoint = endpoint
- res := t.onConnTake(p)
+ res := t.onConnStreamRecvMsg(p)
return func(e error) {
- var p DriverConnTakeDoneInfo
+ var p DriverConnStreamRecvMsgDoneInfo
p.Error = e
res(p)
}
}
-func DriverOnConnDial(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
- var p DriverConnDialStartInfo
+func DriverOnConnStreamSendMsg(t *Driver, c *context.Context, call call) func(error) {
+ var p DriverConnStreamSendMsgStartInfo
p.Context = c
p.Call = call
- p.Endpoint = endpoint
- res := t.onConnDial(p)
+ res := t.onConnStreamSendMsg(p)
return func(e error) {
- var p DriverConnDialDoneInfo
+ var p DriverConnStreamSendMsgDoneInfo
p.Error = e
res(p)
}
}
-func DriverOnConnPark(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
- var p DriverConnParkStartInfo
+func DriverOnConnStreamCloseSend(t *Driver, c *context.Context, call call) func(error) {
+ var p DriverConnStreamCloseSendStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onConnStreamCloseSend(p)
+ return func(e error) {
+ var p DriverConnStreamCloseSendDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func DriverOnConnDial(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
+ var p DriverConnDialStartInfo
p.Context = c
p.Call = call
p.Endpoint = endpoint
- res := t.onConnPark(p)
+ res := t.onConnDial(p)
return func(e error) {
- var p DriverConnParkDoneInfo
+ var p DriverConnDialDoneInfo
p.Error = e
res(p)
}
@@ -1644,6 +1420,18 @@ func DriverOnConnAllow(t *Driver, c *context.Context, call call, endpoint Endpoi
res(p)
}
}
+func DriverOnConnPark(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
+ var p DriverConnParkStartInfo
+ p.Context = c
+ p.Call = call
+ p.Endpoint = endpoint
+ res := t.onConnPark(p)
+ return func(e error) {
+ var p DriverConnParkDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
func DriverOnConnClose(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
var p DriverConnCloseStartInfo
p.Context = c
@@ -1681,18 +1469,6 @@ func DriverOnBalancerInit(t *Driver, c *context.Context, call call, name string)
res(p)
}
}
-func DriverOnBalancerDialEntrypoint(t *Driver, c *context.Context, call call, address string) func(error) {
- var p DriverBalancerDialEntrypointStartInfo
- p.Context = c
- p.Call = call
- p.Address = address
- res := t.onBalancerDialEntrypoint(p)
- return func(e error) {
- var p DriverBalancerDialEntrypointDoneInfo
- p.Error = e
- res(p)
- }
-}
func DriverOnBalancerClose(t *Driver, c *context.Context, call call) func(error) {
var p DriverBalancerCloseStartInfo
p.Context = c
@@ -1728,19 +1504,18 @@ func DriverOnBalancerClusterDiscoveryAttempt(t *Driver, c *context.Context, call
res(p)
}
}
-func DriverOnBalancerUpdate(t *Driver, c *context.Context, call call, needLocalDC bool) func(endpoints []EndpointInfo, added []EndpointInfo, dropped []EndpointInfo, localDC string, _ error) {
+func DriverOnBalancerUpdate(t *Driver, c *context.Context, call call, needLocalDC bool) func(endpoints []EndpointInfo, added []EndpointInfo, dropped []EndpointInfo, localDC string) {
var p DriverBalancerUpdateStartInfo
p.Context = c
p.Call = call
p.NeedLocalDC = needLocalDC
res := t.onBalancerUpdate(p)
- return func(endpoints []EndpointInfo, added []EndpointInfo, dropped []EndpointInfo, localDC string, e error) {
+ return func(endpoints []EndpointInfo, added []EndpointInfo, dropped []EndpointInfo, localDC string) {
var p DriverBalancerUpdateDoneInfo
p.Endpoints = endpoints
p.Added = added
p.Dropped = dropped
p.LocalDC = localDC
- p.Error = e
res(p)
}
}
diff --git a/trace/query.go b/trace/query.go
new file mode 100644
index 000000000..aefb54ddd
--- /dev/null
+++ b/trace/query.go
@@ -0,0 +1,338 @@
+package trace
+
+import (
+ "context"
+)
+
+// tool gtrace used from ./internal/cmd/gtrace
+
+//go:generate gtrace
+
+type (
+ querySessionInfo interface {
+ ID() string
+ NodeID() int64
+ Status() string
+ }
+ queryTransactionInfo interface {
+ ID() string
+ }
+
+ // Query specified trace of retry call activity.
+ // gtrace:gen
+ Query struct {
+ OnNew func(QueryNewStartInfo) func(info QueryNewDoneInfo)
+ OnClose func(QueryCloseStartInfo) func(info QueryCloseDoneInfo)
+
+ OnPoolNew func(QueryPoolNewStartInfo) func(QueryPoolNewDoneInfo)
+ OnPoolClose func(QueryPoolCloseStartInfo) func(QueryPoolCloseDoneInfo)
+ OnPoolTry func(QueryPoolTryStartInfo) func(QueryPoolTryDoneInfo)
+ OnPoolWith func(QueryPoolWithStartInfo) func(QueryPoolWithDoneInfo)
+ OnPoolPut func(QueryPoolPutStartInfo) func(QueryPoolPutDoneInfo)
+ OnPoolGet func(QueryPoolGetStartInfo) func(QueryPoolGetDoneInfo)
+ OnPoolChange func(QueryPoolChange)
+
+ OnDo func(QueryDoStartInfo) func(QueryDoDoneInfo)
+ OnDoTx func(QueryDoTxStartInfo) func(QueryDoTxDoneInfo)
+
+ OnSessionCreate func(QuerySessionCreateStartInfo) func(info QuerySessionCreateDoneInfo)
+ OnSessionAttach func(QuerySessionAttachStartInfo) func(info QuerySessionAttachDoneInfo)
+ OnSessionDelete func(QuerySessionDeleteStartInfo) func(info QuerySessionDeleteDoneInfo)
+ OnSessionExecute func(QuerySessionExecuteStartInfo) func(info QuerySessionExecuteDoneInfo)
+ OnSessionBegin func(QuerySessionBeginStartInfo) func(info QuerySessionBeginDoneInfo)
+ OnTxExecute func(QueryTxExecuteStartInfo) func(info QueryTxExecuteDoneInfo)
+ OnResultNew func(QueryResultNewStartInfo) func(info QueryResultNewDoneInfo)
+ OnResultNextPart func(QueryResultNextPartStartInfo) func(info QueryResultNextPartDoneInfo)
+ OnResultNextResultSet func(QueryResultNextResultSetStartInfo) func(info QueryResultNextResultSetDoneInfo)
+ OnResultClose func(QueryResultCloseStartInfo) func(info QueryResultCloseDoneInfo)
+ OnResultSetNextRow func(QueryResultSetNextRowStartInfo) func(info QueryResultSetNextRowDoneInfo)
+ OnRowScan func(QueryRowScanStartInfo) func(info QueryRowScanDoneInfo)
+ OnRowScanNamed func(QueryRowScanNamedStartInfo) func(info QueryRowScanNamedDoneInfo)
+ OnRowScanStruct func(QueryRowScanStructStartInfo) func(info QueryRowScanStructDoneInfo)
+ }
+
+ QueryDoStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryDoDoneInfo struct {
+ Attempts int
+ Error error
+ }
+ QueryDoTxStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryDoTxDoneInfo struct {
+ Attempts int
+ Error error
+ }
+ QuerySessionCreateStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QuerySessionCreateDoneInfo struct {
+ Session querySessionInfo
+ Error error
+ }
+ QuerySessionExecuteStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Session querySessionInfo
+ Query string
+ }
+ QuerySessionExecuteDoneInfo struct {
+ Error error
+ }
+ QueryTxExecuteStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Session querySessionInfo
+ Tx queryTransactionInfo
+ Query string
+ }
+ QueryTxExecuteDoneInfo struct {
+ Error error
+ }
+ QuerySessionAttachStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ Session querySessionInfo
+ }
+ QuerySessionAttachDoneInfo struct {
+ Error error
+ }
+ QuerySessionBeginStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ Session querySessionInfo
+ }
+ QuerySessionBeginDoneInfo struct {
+ Error error
+ Tx queryTransactionInfo
+ }
+ QueryResultNewStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryResultNewDoneInfo struct {
+ Error error
+ }
+ QueryResultCloseStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryResultCloseDoneInfo struct {
+ Error error
+ }
+ QueryResultNextPartStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryResultNextPartDoneInfo struct {
+ Error error
+ }
+ QueryResultNextResultSetStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryResultNextResultSetDoneInfo struct {
+ Error error
+ }
+ QueryResultSetNextRowStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryResultSetNextRowDoneInfo struct {
+ Error error
+ }
+ QueryRowScanStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryRowScanDoneInfo struct {
+ Error error
+ }
+ QueryRowScanNamedStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryRowScanNamedDoneInfo struct {
+ Error error
+ }
+ QueryRowScanStructStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryRowScanStructDoneInfo struct {
+ Error error
+ }
+ QuerySessionDeleteStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ Session querySessionInfo
+ }
+ QuerySessionDeleteDoneInfo struct {
+ Error error
+ }
+ QueryNewStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryNewDoneInfo struct{}
+ QueryCloseStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryCloseDoneInfo struct {
+ Error error
+ }
+ QueryPoolNewStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryPoolNewDoneInfo struct {
+ Limit int
+ }
+ QueryPoolCloseStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryPoolCloseDoneInfo struct {
+ Error error
+ }
+ QueryPoolTryStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryPoolTryDoneInfo struct {
+ Error error
+ }
+ QueryPoolWithStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryPoolWithDoneInfo struct {
+ Error error
+
+ Attempts int
+ }
+ QueryPoolPutStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryPoolPutDoneInfo struct {
+ Error error
+ }
+ QueryPoolGetStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ QueryPoolGetDoneInfo struct {
+ Error error
+ }
+ QueryPoolChange struct {
+ Limit int
+ Index int
+ Idle int
+ InUse int
+ }
+)
diff --git a/trace/query_gtrace.go b/trace/query_gtrace.go
new file mode 100644
index 000000000..2353b77b4
--- /dev/null
+++ b/trace/query_gtrace.go
@@ -0,0 +1,1544 @@
+// Code generated by gtrace. DO NOT EDIT.
+
+package trace
+
+import (
+ "context"
+)
+
+// queryComposeOptions is a holder of options
+type queryComposeOptions struct {
+ panicCallback func(e interface{})
+}
+
+// QueryOption specified Query compose option
+type QueryComposeOption func(o *queryComposeOptions)
+
+// WithQueryPanicCallback specified behavior on panic
+func WithQueryPanicCallback(cb func(e interface{})) QueryComposeOption {
+ return func(o *queryComposeOptions) {
+ o.panicCallback = cb
+ }
+}
+
+// Compose returns a new Query which has functional fields composed both from t and x.
+func (t *Query) Compose(x *Query, opts ...QueryComposeOption) *Query {
+ var ret Query
+ options := queryComposeOptions{}
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&options)
+ }
+ }
+ {
+ h1 := t.OnNew
+ h2 := x.OnNew
+ ret.OnNew = func(q QueryNewStartInfo) func(QueryNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryNewDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnClose
+ h2 := x.OnClose
+ ret.OnClose = func(q QueryCloseStartInfo) func(QueryCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryCloseDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolNew
+ h2 := x.OnPoolNew
+ ret.OnPoolNew = func(q QueryPoolNewStartInfo) func(QueryPoolNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryPoolNewDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryPoolNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolClose
+ h2 := x.OnPoolClose
+ ret.OnPoolClose = func(q QueryPoolCloseStartInfo) func(QueryPoolCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryPoolCloseDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryPoolCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolTry
+ h2 := x.OnPoolTry
+ ret.OnPoolTry = func(q QueryPoolTryStartInfo) func(QueryPoolTryDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryPoolTryDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryPoolTryDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolWith
+ h2 := x.OnPoolWith
+ ret.OnPoolWith = func(q QueryPoolWithStartInfo) func(QueryPoolWithDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryPoolWithDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryPoolWithDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolPut
+ h2 := x.OnPoolPut
+ ret.OnPoolPut = func(q QueryPoolPutStartInfo) func(QueryPoolPutDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryPoolPutDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryPoolPutDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolGet
+ h2 := x.OnPoolGet
+ ret.OnPoolGet = func(q QueryPoolGetStartInfo) func(QueryPoolGetDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryPoolGetDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryPoolGetDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnPoolChange
+ h2 := x.OnPoolChange
+ ret.OnPoolChange = func(q QueryPoolChange) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(q)
+ }
+ if h2 != nil {
+ h2(q)
+ }
+ }
+ }
+ {
+ h1 := t.OnDo
+ h2 := x.OnDo
+ ret.OnDo = func(q QueryDoStartInfo) func(QueryDoDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryDoDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryDoDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnDoTx
+ h2 := x.OnDoTx
+ ret.OnDoTx = func(q QueryDoTxStartInfo) func(QueryDoTxDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryDoTxDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(q QueryDoTxDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(q)
+ }
+ if r1 != nil {
+ r1(q)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionCreate
+ h2 := x.OnSessionCreate
+ ret.OnSessionCreate = func(q QuerySessionCreateStartInfo) func(QuerySessionCreateDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QuerySessionCreateDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QuerySessionCreateDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionAttach
+ h2 := x.OnSessionAttach
+ ret.OnSessionAttach = func(q QuerySessionAttachStartInfo) func(QuerySessionAttachDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QuerySessionAttachDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QuerySessionAttachDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionDelete
+ h2 := x.OnSessionDelete
+ ret.OnSessionDelete = func(q QuerySessionDeleteStartInfo) func(QuerySessionDeleteDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QuerySessionDeleteDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QuerySessionDeleteDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionExecute
+ h2 := x.OnSessionExecute
+ ret.OnSessionExecute = func(q QuerySessionExecuteStartInfo) func(QuerySessionExecuteDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QuerySessionExecuteDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QuerySessionExecuteDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionBegin
+ h2 := x.OnSessionBegin
+ ret.OnSessionBegin = func(q QuerySessionBeginStartInfo) func(QuerySessionBeginDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QuerySessionBeginDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QuerySessionBeginDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnTxExecute
+ h2 := x.OnTxExecute
+ ret.OnTxExecute = func(q QueryTxExecuteStartInfo) func(QueryTxExecuteDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryTxExecuteDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryTxExecuteDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnResultNew
+ h2 := x.OnResultNew
+ ret.OnResultNew = func(q QueryResultNewStartInfo) func(QueryResultNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryResultNewDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryResultNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnResultNextPart
+ h2 := x.OnResultNextPart
+ ret.OnResultNextPart = func(q QueryResultNextPartStartInfo) func(QueryResultNextPartDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryResultNextPartDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryResultNextPartDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnResultNextResultSet
+ h2 := x.OnResultNextResultSet
+ ret.OnResultNextResultSet = func(q QueryResultNextResultSetStartInfo) func(QueryResultNextResultSetDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryResultNextResultSetDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryResultNextResultSetDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnResultClose
+ h2 := x.OnResultClose
+ ret.OnResultClose = func(q QueryResultCloseStartInfo) func(QueryResultCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryResultCloseDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryResultCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnResultSetNextRow
+ h2 := x.OnResultSetNextRow
+ ret.OnResultSetNextRow = func(q QueryResultSetNextRowStartInfo) func(QueryResultSetNextRowDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryResultSetNextRowDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryResultSetNextRowDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnRowScan
+ h2 := x.OnRowScan
+ ret.OnRowScan = func(q QueryRowScanStartInfo) func(QueryRowScanDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryRowScanDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryRowScanDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnRowScanNamed
+ h2 := x.OnRowScanNamed
+ ret.OnRowScanNamed = func(q QueryRowScanNamedStartInfo) func(QueryRowScanNamedDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryRowScanNamedDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryRowScanNamedDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnRowScanStruct
+ h2 := x.OnRowScanStruct
+ ret.OnRowScanStruct = func(q QueryRowScanStructStartInfo) func(QueryRowScanStructDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(QueryRowScanStructDoneInfo)
+ if h1 != nil {
+ r = h1(q)
+ }
+ if h2 != nil {
+ r1 = h2(q)
+ }
+ return func(info QueryRowScanStructDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(info)
+ }
+ if r1 != nil {
+ r1(info)
+ }
+ }
+ }
+ }
+ return &ret
+}
+func (t *Query) onNew(q QueryNewStartInfo) func(info QueryNewDoneInfo) {
+ fn := t.OnNew
+ if fn == nil {
+ return func(QueryNewDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryNewDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onClose(q QueryCloseStartInfo) func(info QueryCloseDoneInfo) {
+ fn := t.OnClose
+ if fn == nil {
+ return func(QueryCloseDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryCloseDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolNew(q QueryPoolNewStartInfo) func(QueryPoolNewDoneInfo) {
+ fn := t.OnPoolNew
+ if fn == nil {
+ return func(QueryPoolNewDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryPoolNewDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolClose(q QueryPoolCloseStartInfo) func(QueryPoolCloseDoneInfo) {
+ fn := t.OnPoolClose
+ if fn == nil {
+ return func(QueryPoolCloseDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryPoolCloseDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolTry(q QueryPoolTryStartInfo) func(QueryPoolTryDoneInfo) {
+ fn := t.OnPoolTry
+ if fn == nil {
+ return func(QueryPoolTryDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryPoolTryDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolWith(q QueryPoolWithStartInfo) func(QueryPoolWithDoneInfo) {
+ fn := t.OnPoolWith
+ if fn == nil {
+ return func(QueryPoolWithDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryPoolWithDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolPut(q QueryPoolPutStartInfo) func(QueryPoolPutDoneInfo) {
+ fn := t.OnPoolPut
+ if fn == nil {
+ return func(QueryPoolPutDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryPoolPutDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolGet(q QueryPoolGetStartInfo) func(QueryPoolGetDoneInfo) {
+ fn := t.OnPoolGet
+ if fn == nil {
+ return func(QueryPoolGetDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryPoolGetDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onPoolChange(q QueryPoolChange) {
+ fn := t.OnPoolChange
+ if fn == nil {
+ return
+ }
+ fn(q)
+}
+func (t *Query) onDo(q QueryDoStartInfo) func(QueryDoDoneInfo) {
+ fn := t.OnDo
+ if fn == nil {
+ return func(QueryDoDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryDoDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onDoTx(q QueryDoTxStartInfo) func(QueryDoTxDoneInfo) {
+ fn := t.OnDoTx
+ if fn == nil {
+ return func(QueryDoTxDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryDoTxDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onSessionCreate(q QuerySessionCreateStartInfo) func(info QuerySessionCreateDoneInfo) {
+ fn := t.OnSessionCreate
+ if fn == nil {
+ return func(QuerySessionCreateDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QuerySessionCreateDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onSessionAttach(q QuerySessionAttachStartInfo) func(info QuerySessionAttachDoneInfo) {
+ fn := t.OnSessionAttach
+ if fn == nil {
+ return func(QuerySessionAttachDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QuerySessionAttachDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onSessionDelete(q QuerySessionDeleteStartInfo) func(info QuerySessionDeleteDoneInfo) {
+ fn := t.OnSessionDelete
+ if fn == nil {
+ return func(QuerySessionDeleteDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QuerySessionDeleteDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onSessionExecute(q QuerySessionExecuteStartInfo) func(info QuerySessionExecuteDoneInfo) {
+ fn := t.OnSessionExecute
+ if fn == nil {
+ return func(QuerySessionExecuteDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QuerySessionExecuteDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onSessionBegin(q QuerySessionBeginStartInfo) func(info QuerySessionBeginDoneInfo) {
+ fn := t.OnSessionBegin
+ if fn == nil {
+ return func(QuerySessionBeginDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QuerySessionBeginDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onTxExecute(q QueryTxExecuteStartInfo) func(info QueryTxExecuteDoneInfo) {
+ fn := t.OnTxExecute
+ if fn == nil {
+ return func(QueryTxExecuteDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryTxExecuteDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onResultNew(q QueryResultNewStartInfo) func(info QueryResultNewDoneInfo) {
+ fn := t.OnResultNew
+ if fn == nil {
+ return func(QueryResultNewDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryResultNewDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onResultNextPart(q QueryResultNextPartStartInfo) func(info QueryResultNextPartDoneInfo) {
+ fn := t.OnResultNextPart
+ if fn == nil {
+ return func(QueryResultNextPartDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryResultNextPartDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onResultNextResultSet(q QueryResultNextResultSetStartInfo) func(info QueryResultNextResultSetDoneInfo) {
+ fn := t.OnResultNextResultSet
+ if fn == nil {
+ return func(QueryResultNextResultSetDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryResultNextResultSetDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onResultClose(q QueryResultCloseStartInfo) func(info QueryResultCloseDoneInfo) {
+ fn := t.OnResultClose
+ if fn == nil {
+ return func(QueryResultCloseDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryResultCloseDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onResultSetNextRow(q QueryResultSetNextRowStartInfo) func(info QueryResultSetNextRowDoneInfo) {
+ fn := t.OnResultSetNextRow
+ if fn == nil {
+ return func(QueryResultSetNextRowDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryResultSetNextRowDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onRowScan(q QueryRowScanStartInfo) func(info QueryRowScanDoneInfo) {
+ fn := t.OnRowScan
+ if fn == nil {
+ return func(QueryRowScanDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryRowScanDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onRowScanNamed(q QueryRowScanNamedStartInfo) func(info QueryRowScanNamedDoneInfo) {
+ fn := t.OnRowScanNamed
+ if fn == nil {
+ return func(QueryRowScanNamedDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryRowScanNamedDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Query) onRowScanStruct(q QueryRowScanStructStartInfo) func(info QueryRowScanStructDoneInfo) {
+ fn := t.OnRowScanStruct
+ if fn == nil {
+ return func(QueryRowScanStructDoneInfo) {
+ return
+ }
+ }
+ res := fn(q)
+ if res == nil {
+ return func(QueryRowScanStructDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func QueryOnNew(t *Query, c *context.Context, call call) func() {
+ var p QueryNewStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onNew(p)
+ return func() {
+ var p QueryNewDoneInfo
+ res(p)
+ }
+}
+func QueryOnClose(t *Query, c *context.Context, call call) func(error) {
+ var p QueryCloseStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onClose(p)
+ return func(e error) {
+ var p QueryCloseDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnPoolNew(t *Query, c *context.Context, call call) func(limit int) {
+ var p QueryPoolNewStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onPoolNew(p)
+ return func(limit int) {
+ var p QueryPoolNewDoneInfo
+ p.Limit = limit
+ res(p)
+ }
+}
+func QueryOnPoolClose(t *Query, c *context.Context, call call) func(error) {
+ var p QueryPoolCloseStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onPoolClose(p)
+ return func(e error) {
+ var p QueryPoolCloseDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnPoolTry(t *Query, c *context.Context, call call) func(error) {
+ var p QueryPoolTryStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onPoolTry(p)
+ return func(e error) {
+ var p QueryPoolTryDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnPoolWith(t *Query, c *context.Context, call call) func(_ error, attempts int) {
+ var p QueryPoolWithStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onPoolWith(p)
+ return func(e error, attempts int) {
+ var p QueryPoolWithDoneInfo
+ p.Error = e
+ p.Attempts = attempts
+ res(p)
+ }
+}
+func QueryOnPoolPut(t *Query, c *context.Context, call call) func(error) {
+ var p QueryPoolPutStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onPoolPut(p)
+ return func(e error) {
+ var p QueryPoolPutDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnPoolGet(t *Query, c *context.Context, call call) func(error) {
+ var p QueryPoolGetStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onPoolGet(p)
+ return func(e error) {
+ var p QueryPoolGetDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnPoolChange(t *Query, limit int, index int, idle int, inUse int) {
+ var p QueryPoolChange
+ p.Limit = limit
+ p.Index = index
+ p.Idle = idle
+ p.InUse = inUse
+ t.onPoolChange(p)
+}
+func QueryOnDo(t *Query, c *context.Context, call call) func(attempts int, _ error) {
+ var p QueryDoStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onDo(p)
+ return func(attempts int, e error) {
+ var p QueryDoDoneInfo
+ p.Attempts = attempts
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnDoTx(t *Query, c *context.Context, call call) func(attempts int, _ error) {
+ var p QueryDoTxStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onDoTx(p)
+ return func(attempts int, e error) {
+ var p QueryDoTxDoneInfo
+ p.Attempts = attempts
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnSessionCreate(t *Query, c *context.Context, call call) func(session querySessionInfo, _ error) {
+ var p QuerySessionCreateStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onSessionCreate(p)
+ return func(session querySessionInfo, e error) {
+ var p QuerySessionCreateDoneInfo
+ p.Session = session
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnSessionAttach(t *Query, c *context.Context, call call, session querySessionInfo) func(error) {
+ var p QuerySessionAttachStartInfo
+ p.Context = c
+ p.Call = call
+ p.Session = session
+ res := t.onSessionAttach(p)
+ return func(e error) {
+ var p QuerySessionAttachDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnSessionDelete(t *Query, c *context.Context, call call, session querySessionInfo) func(error) {
+ var p QuerySessionDeleteStartInfo
+ p.Context = c
+ p.Call = call
+ p.Session = session
+ res := t.onSessionDelete(p)
+ return func(e error) {
+ var p QuerySessionDeleteDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnSessionExecute(t *Query, c *context.Context, call call, session querySessionInfo, query string) func(error) {
+ var p QuerySessionExecuteStartInfo
+ p.Context = c
+ p.Call = call
+ p.Session = session
+ p.Query = query
+ res := t.onSessionExecute(p)
+ return func(e error) {
+ var p QuerySessionExecuteDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnSessionBegin(t *Query, c *context.Context, call call, session querySessionInfo) func(_ error, tx queryTransactionInfo) {
+ var p QuerySessionBeginStartInfo
+ p.Context = c
+ p.Call = call
+ p.Session = session
+ res := t.onSessionBegin(p)
+ return func(e error, tx queryTransactionInfo) {
+ var p QuerySessionBeginDoneInfo
+ p.Error = e
+ p.Tx = tx
+ res(p)
+ }
+}
+func QueryOnTxExecute(t *Query, c *context.Context, call call, session querySessionInfo, tx queryTransactionInfo, query string) func(error) {
+ var p QueryTxExecuteStartInfo
+ p.Context = c
+ p.Call = call
+ p.Session = session
+ p.Tx = tx
+ p.Query = query
+ res := t.onTxExecute(p)
+ return func(e error) {
+ var p QueryTxExecuteDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnResultNew(t *Query, c *context.Context, call call) func(error) {
+ var p QueryResultNewStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onResultNew(p)
+ return func(e error) {
+ var p QueryResultNewDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnResultNextPart(t *Query, c *context.Context, call call) func(error) {
+ var p QueryResultNextPartStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onResultNextPart(p)
+ return func(e error) {
+ var p QueryResultNextPartDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnResultNextResultSet(t *Query, c *context.Context, call call) func(error) {
+ var p QueryResultNextResultSetStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onResultNextResultSet(p)
+ return func(e error) {
+ var p QueryResultNextResultSetDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnResultClose(t *Query, c *context.Context, call call) func(error) {
+ var p QueryResultCloseStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onResultClose(p)
+ return func(e error) {
+ var p QueryResultCloseDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnResultSetNextRow(t *Query, c *context.Context, call call) func(error) {
+ var p QueryResultSetNextRowStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onResultSetNextRow(p)
+ return func(e error) {
+ var p QueryResultSetNextRowDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnRowScan(t *Query, c *context.Context, call call) func(error) {
+ var p QueryRowScanStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onRowScan(p)
+ return func(e error) {
+ var p QueryRowScanDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnRowScanNamed(t *Query, c *context.Context, call call) func(error) {
+ var p QueryRowScanNamedStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onRowScanNamed(p)
+ return func(e error) {
+ var p QueryRowScanNamedDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+func QueryOnRowScanStruct(t *Query, c *context.Context, call call) func(error) {
+ var p QueryRowScanStructStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onRowScanStruct(p)
+ return func(e error) {
+ var p QueryRowScanStructDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
diff --git a/trace/retry.go b/trace/retry.go
index 0ac2c483b..c87a149d2 100644
--- a/trace/retry.go
+++ b/trace/retry.go
@@ -12,7 +12,7 @@ type (
// Retry specified trace of retry call activity.
// gtrace:gen
Retry struct {
- OnRetry func(RetryLoopStartInfo) func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo)
+ OnRetry func(RetryLoopStartInfo) func(RetryLoopDoneInfo)
}
RetryLoopStartInfo struct {
// Context make available context in trace callback function.
@@ -21,18 +21,12 @@ type (
// Safe replacement of context are provided only inside callback function
Context *context.Context
- // Deprecated: use Label field instead
- ID string
-
Call call
Label string
Idempotent bool
NestedCall bool // a sign for detect Retry calls inside head Retry
}
- RetryLoopIntermediateInfo struct {
- Error error
- }
RetryLoopDoneInfo struct {
Attempts int
Error error
diff --git a/trace/retry_gtrace.go b/trace/retry_gtrace.go
index ea80a385f..14a35e413 100644
--- a/trace/retry_gtrace.go
+++ b/trace/retry_gtrace.go
@@ -33,7 +33,7 @@ func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
{
h1 := t.OnRetry
h2 := x.OnRetry
- ret.OnRetry = func(r RetryLoopStartInfo) func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
+ ret.OnRetry = func(r RetryLoopStartInfo) func(RetryLoopDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -41,14 +41,14 @@ func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
}
}()
}
- var r1, r2 func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo)
+ var r1, r2 func(RetryLoopDoneInfo)
if h1 != nil {
r1 = h1(r)
}
if h2 != nil {
r2 = h2(r)
}
- return func(r RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
+ return func(r RetryLoopDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -56,78 +56,44 @@ func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
}
}()
}
- var r3, r4 func(RetryLoopDoneInfo)
if r1 != nil {
- r3 = r1(r)
+ r1(r)
}
if r2 != nil {
- r4 = r2(r)
- }
- return func(r RetryLoopDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r3 != nil {
- r3(r)
- }
- if r4 != nil {
- r4(r)
- }
+ r2(r)
}
}
}
}
return &ret
}
-func (t *Retry) onRetry(r RetryLoopStartInfo) func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
+func (t *Retry) onRetry(r RetryLoopStartInfo) func(RetryLoopDoneInfo) {
fn := t.OnRetry
if fn == nil {
- return func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
- return func(RetryLoopDoneInfo) {
- return
- }
+ return func(RetryLoopDoneInfo) {
+ return
}
}
res := fn(r)
if res == nil {
- return func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
- return func(RetryLoopDoneInfo) {
- return
- }
+ return func(RetryLoopDoneInfo) {
+ return
}
}
- return func(r RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
- res := res(r)
- if res == nil {
- return func(RetryLoopDoneInfo) {
- return
- }
- }
- return res
- }
+ return res
}
-func RetryOnRetry(t *Retry, c *context.Context, iD string, call call, label string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) {
+func RetryOnRetry(t *Retry, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(attempts int, _ error) {
var p RetryLoopStartInfo
p.Context = c
- p.ID = iD
p.Call = call
p.Label = label
p.Idempotent = idempotent
p.NestedCall = nestedCall
res := t.onRetry(p)
- return func(e error) func(int, error) {
- var p RetryLoopIntermediateInfo
+ return func(attempts int, e error) {
+ var p RetryLoopDoneInfo
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(attempts int, e error) {
- var p RetryLoopDoneInfo
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
diff --git a/trace/sql.go b/trace/sql.go
index d98c905b5..e6d5de6ec 100644
--- a/trace/sql.go
+++ b/trace/sql.go
@@ -159,9 +159,6 @@ type (
TxContext context.Context
Tx tableTransactionInfo
Query string
-
- // Deprecated: all transactions are idempotent
- Idempotent bool
}
DatabaseSQLTxQueryDoneInfo struct {
Error error
@@ -176,9 +173,6 @@ type (
TxContext context.Context
Tx tableTransactionInfo
Query string
-
- // Deprecated: all transactions are idempotent
- Idempotent bool
}
DatabaseSQLTxExecDoneInfo struct {
Error error
diff --git a/trace/sql_gtrace.go b/trace/sql_gtrace.go
index a9e59a2ef..e5d2a484f 100644
--- a/trace/sql_gtrace.go
+++ b/trace/sql_gtrace.go
@@ -1012,14 +1012,13 @@ func DatabaseSQLOnConnIsTableExists(t *DatabaseSQL, c *context.Context, call cal
res(p)
}
}
-func DatabaseSQLOnTxQuery(t *DatabaseSQL, c *context.Context, call call, txContext context.Context, tx tableTransactionInfo, query string, idempotent bool) func(error) {
+func DatabaseSQLOnTxQuery(t *DatabaseSQL, c *context.Context, call call, txContext context.Context, tx tableTransactionInfo, query string) func(error) {
var p DatabaseSQLTxQueryStartInfo
p.Context = c
p.Call = call
p.TxContext = txContext
p.Tx = tx
p.Query = query
- p.Idempotent = idempotent
res := t.onTxQuery(p)
return func(e error) {
var p DatabaseSQLTxQueryDoneInfo
@@ -1027,14 +1026,13 @@ func DatabaseSQLOnTxQuery(t *DatabaseSQL, c *context.Context, call call, txConte
res(p)
}
}
-func DatabaseSQLOnTxExec(t *DatabaseSQL, c *context.Context, call call, txContext context.Context, tx tableTransactionInfo, query string, idempotent bool) func(error) {
+func DatabaseSQLOnTxExec(t *DatabaseSQL, c *context.Context, call call, txContext context.Context, tx tableTransactionInfo, query string) func(error) {
var p DatabaseSQLTxExecStartInfo
p.Context = c
p.Call = call
p.TxContext = txContext
p.Tx = tx
p.Query = query
- p.Idempotent = idempotent
res := t.onTxExec(p)
return func(e error) {
var p DatabaseSQLTxExecDoneInfo
diff --git a/trace/table.go b/trace/table.go
index 81e298324..4e944435a 100644
--- a/trace/table.go
+++ b/trace/table.go
@@ -16,15 +16,9 @@ type (
// Client events
OnInit func(TableInitStartInfo) func(TableInitDoneInfo)
OnClose func(TableCloseStartInfo) func(TableCloseDoneInfo)
- OnDo func(TableDoStartInfo) func(info TableDoIntermediateInfo) func(TableDoDoneInfo)
- OnDoTx func(TableDoTxStartInfo) func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo)
- OnCreateSession func(
- TableCreateSessionStartInfo,
- ) func(
- info TableCreateSessionIntermediateInfo,
- ) func(
- TableCreateSessionDoneInfo,
- )
+ OnDo func(TableDoStartInfo) func(TableDoDoneInfo)
+ OnDoTx func(TableDoTxStartInfo) func(TableDoTxDoneInfo)
+ OnCreateSession func(TableCreateSessionStartInfo) func(TableCreateSessionDoneInfo)
// Session events
OnSessionNew func(TableSessionNewStartInfo) func(TableSessionNewDoneInfo)
OnSessionDelete func(TableSessionDeleteStartInfo) func(TableSessionDeleteDoneInfo)
@@ -35,36 +29,22 @@ type (
OnSessionQueryExecute func(TableExecuteDataQueryStartInfo) func(TableExecuteDataQueryDoneInfo)
OnSessionQueryExplain func(TableExplainQueryStartInfo) func(TableExplainQueryDoneInfo)
// Stream events
- OnSessionQueryStreamExecute func(
- TableSessionQueryStreamExecuteStartInfo,
- ) func(
- TableSessionQueryStreamExecuteIntermediateInfo,
- ) func(
- TableSessionQueryStreamExecuteDoneInfo,
- )
- OnSessionQueryStreamRead func(
- TableSessionQueryStreamReadStartInfo,
- ) func(
- TableSessionQueryStreamReadIntermediateInfo,
- ) func(
- TableSessionQueryStreamReadDoneInfo,
- )
+ OnSessionQueryStreamExecute func(TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteDoneInfo)
+ OnSessionQueryStreamRead func(TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadDoneInfo)
// Transaction events
- OnSessionTransactionBegin func(TableSessionTransactionBeginStartInfo) func(
- TableSessionTransactionBeginDoneInfo,
+ OnTxBegin func(TableTxBeginStartInfo) func(
+ TableTxBeginDoneInfo,
)
- OnSessionTransactionExecute func(TableTransactionExecuteStartInfo) func(
+ OnTxExecute func(TableTransactionExecuteStartInfo) func(
TableTransactionExecuteDoneInfo,
)
- OnSessionTransactionExecuteStatement func(TableTransactionExecuteStatementStartInfo) func(
+ OnTxExecuteStatement func(TableTransactionExecuteStatementStartInfo) func(
TableTransactionExecuteStatementDoneInfo,
)
- OnSessionTransactionCommit func(TableSessionTransactionCommitStartInfo) func(
- TableSessionTransactionCommitDoneInfo,
- )
- OnSessionTransactionRollback func(TableSessionTransactionRollbackStartInfo) func(
- TableSessionTransactionRollbackDoneInfo,
+ OnTxCommit func(TableTxCommitStartInfo) func(
+ TableTxCommitDoneInfo,
)
+ OnTxRollback func(TableTxRollbackStartInfo) func(TableTxRollbackDoneInfo)
// Pool state event
OnPoolStateChange func(TablePoolStateChangeInfo)
@@ -72,16 +52,6 @@ type (
OnPoolSessionAdd func(info TablePoolSessionAddInfo)
OnPoolSessionRemove func(info TablePoolSessionRemoveInfo)
- // OnPoolSessionNew is user-defined callback for listening events about creating sessions with
- // internal session pool calls
- //
- // Deprecated: use OnPoolSessionAdd callback
- OnPoolSessionNew func(TablePoolSessionNewStartInfo) func(TablePoolSessionNewDoneInfo)
-
- // OnPoolSessionClose is user-defined callback for listening sessionClose calls
- //
- // Deprecated: use OnPoolSessionRemove callback
- OnPoolSessionClose func(TablePoolSessionCloseStartInfo) func(TablePoolSessionCloseDoneInfo)
// Pool common API events
OnPoolPut func(TablePoolPutStartInfo) func(TablePoolPutDoneInfo)
OnPoolGet func(TablePoolGetStartInfo) func(TablePoolGetDoneInfo)
@@ -250,9 +220,6 @@ type (
Call call
Session tableSessionInfo
}
- TableSessionQueryStreamReadIntermediateInfo struct {
- Error error
- }
TableSessionQueryStreamReadDoneInfo struct {
Error error
}
@@ -267,13 +234,10 @@ type (
Query tableDataQuery
Parameters tableQueryParameters
}
- TableSessionQueryStreamExecuteIntermediateInfo struct {
- Error error
- }
TableSessionQueryStreamExecuteDoneInfo struct {
Error error
}
- TableSessionTransactionBeginStartInfo struct {
+ TableTxBeginStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
// Warning: concurrent access to pointer on client side must be excluded.
@@ -282,11 +246,11 @@ type (
Call call
Session tableSessionInfo
}
- TableSessionTransactionBeginDoneInfo struct {
+ TableTxBeginDoneInfo struct {
Tx tableTransactionInfo
Error error
}
- TableSessionTransactionCommitStartInfo struct {
+ TableTxCommitStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
// Warning: concurrent access to pointer on client side must be excluded.
@@ -296,10 +260,10 @@ type (
Session tableSessionInfo
Tx tableTransactionInfo
}
- TableSessionTransactionCommitDoneInfo struct {
+ TableTxCommitDoneInfo struct {
Error error
}
- TableSessionTransactionRollbackStartInfo struct {
+ TableTxRollbackStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
// Warning: concurrent access to pointer on client side must be excluded.
@@ -309,7 +273,7 @@ type (
Session tableSessionInfo
Tx tableTransactionInfo
}
- TableSessionTransactionRollbackDoneInfo struct {
+ TableTxRollbackDoneInfo struct {
Error error
}
TableInitStartInfo struct {
@@ -322,7 +286,6 @@ type (
}
TableInitDoneInfo struct {
Limit int
- Error error
}
TablePoolStateChangeInfo struct {
Size int
@@ -415,16 +378,10 @@ type (
Context *context.Context
Call call
- // Deprecated: use Label field instead
- ID string
-
Label string
Idempotent bool
NestedCall bool // flag when Retry called inside head Retry
}
- TableDoIntermediateInfo struct {
- Error error
- }
TableDoDoneInfo struct {
Attempts int
Error error
@@ -437,16 +394,10 @@ type (
Context *context.Context
Call call
- // Deprecated: use Label field instead
- ID string
-
Label string
Idempotent bool
NestedCall bool // flag when Retry called inside head Retry
}
- TableDoTxIntermediateInfo struct {
- Error error
- }
TableDoTxDoneInfo struct {
Attempts int
Error error
@@ -459,9 +410,6 @@ type (
Context *context.Context
Call call
}
- TableCreateSessionIntermediateInfo struct {
- Error error
- }
TableCreateSessionDoneInfo struct {
Session tableSessionInfo
Attempts int
diff --git a/trace/table_gtrace.go b/trace/table_gtrace.go
index 95630c8f8..6834d38b9 100644
--- a/trace/table_gtrace.go
+++ b/trace/table_gtrace.go
@@ -103,7 +103,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnDo
h2 := x.OnDo
- ret.OnDo = func(t TableDoStartInfo) func(TableDoIntermediateInfo) func(TableDoDoneInfo) {
+ ret.OnDo = func(t TableDoStartInfo) func(TableDoDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -111,14 +111,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableDoIntermediateInfo) func(TableDoDoneInfo)
+ var r, r1 func(TableDoDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(info TableDoIntermediateInfo) func(TableDoDoneInfo) {
+ return func(t TableDoDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -126,27 +126,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableDoDoneInfo)
if r != nil {
- r2 = r(info)
+ r(t)
}
if r1 != nil {
- r3 = r1(info)
- }
- return func(t TableDoDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -154,7 +138,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnDoTx
h2 := x.OnDoTx
- ret.OnDoTx = func(t TableDoTxStartInfo) func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
+ ret.OnDoTx = func(t TableDoTxStartInfo) func(TableDoTxDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -162,14 +146,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo)
+ var r, r1 func(TableDoTxDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
+ return func(t TableDoTxDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -177,27 +161,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableDoTxDoneInfo)
if r != nil {
- r2 = r(info)
+ r(t)
}
if r1 != nil {
- r3 = r1(info)
- }
- return func(t TableDoTxDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -205,7 +173,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnCreateSession
h2 := x.OnCreateSession
- ret.OnCreateSession = func(t TableCreateSessionStartInfo) func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
+ ret.OnCreateSession = func(t TableCreateSessionStartInfo) func(TableCreateSessionDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -213,14 +181,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo)
+ var r, r1 func(TableCreateSessionDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(info TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
+ return func(t TableCreateSessionDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -228,27 +196,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableCreateSessionDoneInfo)
if r != nil {
- r2 = r(info)
+ r(t)
}
if r1 != nil {
- r3 = r1(info)
- }
- return func(t TableCreateSessionDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -501,7 +453,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnSessionQueryStreamExecute
h2 := x.OnSessionQueryStreamExecute
- ret.OnSessionQueryStreamExecute = func(t TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
+ ret.OnSessionQueryStreamExecute = func(t TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -509,14 +461,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo)
+ var r, r1 func(TableSessionQueryStreamExecuteDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
+ return func(t TableSessionQueryStreamExecuteDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -524,27 +476,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableSessionQueryStreamExecuteDoneInfo)
if r != nil {
- r2 = r(t)
+ r(t)
}
if r1 != nil {
- r3 = r1(t)
- }
- return func(t TableSessionQueryStreamExecuteDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -552,7 +488,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnSessionQueryStreamRead
h2 := x.OnSessionQueryStreamRead
- ret.OnSessionQueryStreamRead = func(t TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
+ ret.OnSessionQueryStreamRead = func(t TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -560,14 +496,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo)
+ var r, r1 func(TableSessionQueryStreamReadDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
+ return func(t TableSessionQueryStreamReadDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -575,35 +511,19 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableSessionQueryStreamReadDoneInfo)
if r != nil {
- r2 = r(t)
+ r(t)
}
if r1 != nil {
- r3 = r1(t)
- }
- return func(t TableSessionQueryStreamReadDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
}
{
- h1 := t.OnSessionTransactionBegin
- h2 := x.OnSessionTransactionBegin
- ret.OnSessionTransactionBegin = func(t TableSessionTransactionBeginStartInfo) func(TableSessionTransactionBeginDoneInfo) {
+ h1 := t.OnTxBegin
+ h2 := x.OnTxBegin
+ ret.OnTxBegin = func(t TableTxBeginStartInfo) func(TableTxBeginDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -611,14 +531,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionTransactionBeginDoneInfo)
+ var r, r1 func(TableTxBeginDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionTransactionBeginDoneInfo) {
+ return func(t TableTxBeginDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -636,9 +556,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionExecute
- h2 := x.OnSessionTransactionExecute
- ret.OnSessionTransactionExecute = func(t TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
+ h1 := t.OnTxExecute
+ h2 := x.OnTxExecute
+ ret.OnTxExecute = func(t TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -671,9 +591,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionExecuteStatement
- h2 := x.OnSessionTransactionExecuteStatement
- ret.OnSessionTransactionExecuteStatement = func(t TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
+ h1 := t.OnTxExecuteStatement
+ h2 := x.OnTxExecuteStatement
+ ret.OnTxExecuteStatement = func(t TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -706,9 +626,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionCommit
- h2 := x.OnSessionTransactionCommit
- ret.OnSessionTransactionCommit = func(t TableSessionTransactionCommitStartInfo) func(TableSessionTransactionCommitDoneInfo) {
+ h1 := t.OnTxCommit
+ h2 := x.OnTxCommit
+ ret.OnTxCommit = func(t TableTxCommitStartInfo) func(TableTxCommitDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -716,14 +636,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionTransactionCommitDoneInfo)
+ var r, r1 func(TableTxCommitDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionTransactionCommitDoneInfo) {
+ return func(t TableTxCommitDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -741,9 +661,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionRollback
- h2 := x.OnSessionTransactionRollback
- ret.OnSessionTransactionRollback = func(t TableSessionTransactionRollbackStartInfo) func(TableSessionTransactionRollbackDoneInfo) {
+ h1 := t.OnTxRollback
+ h2 := x.OnTxRollback
+ ret.OnTxRollback = func(t TableTxRollbackStartInfo) func(TableTxRollbackDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -751,14 +671,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionTransactionRollbackDoneInfo)
+ var r, r1 func(TableTxRollbackDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionTransactionRollbackDoneInfo) {
+ return func(t TableTxRollbackDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -832,76 +752,6 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
}
- {
- h1 := t.OnPoolSessionNew
- h2 := x.OnPoolSessionNew
- ret.OnPoolSessionNew = func(t TablePoolSessionNewStartInfo) func(TablePoolSessionNewDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- var r, r1 func(TablePoolSessionNewDoneInfo)
- if h1 != nil {
- r = h1(t)
- }
- if h2 != nil {
- r1 = h2(t)
- }
- return func(t TablePoolSessionNewDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r != nil {
- r(t)
- }
- if r1 != nil {
- r1(t)
- }
- }
- }
- }
- {
- h1 := t.OnPoolSessionClose
- h2 := x.OnPoolSessionClose
- ret.OnPoolSessionClose = func(t TablePoolSessionCloseStartInfo) func(TablePoolSessionCloseDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- var r, r1 func(TablePoolSessionCloseDoneInfo)
- if h1 != nil {
- r = h1(t)
- }
- if h2 != nil {
- r1 = h2(t)
- }
- return func(t TablePoolSessionCloseDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r != nil {
- r(t)
- }
- if r1 != nil {
- r1(t)
- }
- }
- }
- }
{
h1 := t.OnPoolPut
h2 := x.OnPoolPut
@@ -1039,86 +889,50 @@ func (t *Table) onClose(t1 TableCloseStartInfo) func(TableCloseDoneInfo) {
}
return res
}
-func (t *Table) onDo(t1 TableDoStartInfo) func(info TableDoIntermediateInfo) func(TableDoDoneInfo) {
+func (t *Table) onDo(t1 TableDoStartInfo) func(TableDoDoneInfo) {
fn := t.OnDo
if fn == nil {
- return func(TableDoIntermediateInfo) func(TableDoDoneInfo) {
- return func(TableDoDoneInfo) {
- return
- }
+ return func(TableDoDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableDoIntermediateInfo) func(TableDoDoneInfo) {
- return func(TableDoDoneInfo) {
- return
- }
- }
- }
- return func(info TableDoIntermediateInfo) func(TableDoDoneInfo) {
- res := res(info)
- if res == nil {
- return func(TableDoDoneInfo) {
- return
- }
+ return func(TableDoDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onDoTx(t1 TableDoTxStartInfo) func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
+func (t *Table) onDoTx(t1 TableDoTxStartInfo) func(TableDoTxDoneInfo) {
fn := t.OnDoTx
if fn == nil {
- return func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
- return func(TableDoTxDoneInfo) {
- return
- }
+ return func(TableDoTxDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
- return func(TableDoTxDoneInfo) {
- return
- }
- }
- }
- return func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
- res := res(info)
- if res == nil {
- return func(TableDoTxDoneInfo) {
- return
- }
+ return func(TableDoTxDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onCreateSession(t1 TableCreateSessionStartInfo) func(info TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
+func (t *Table) onCreateSession(t1 TableCreateSessionStartInfo) func(TableCreateSessionDoneInfo) {
fn := t.OnCreateSession
if fn == nil {
- return func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
- return func(TableCreateSessionDoneInfo) {
- return
- }
+ return func(TableCreateSessionDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
- return func(TableCreateSessionDoneInfo) {
- return
- }
- }
- }
- return func(info TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
- res := res(info)
- if res == nil {
- return func(TableCreateSessionDoneInfo) {
- return
- }
+ return func(TableCreateSessionDoneInfo) {
+ return
}
- return res
}
+ return res
}
func (t *Table) onSessionNew(t1 TableSessionNewStartInfo) func(TableSessionNewDoneInfo) {
fn := t.OnSessionNew
@@ -1225,77 +1039,53 @@ func (t *Table) onSessionQueryExplain(t1 TableExplainQueryStartInfo) func(TableE
}
return res
}
-func (t *Table) onSessionQueryStreamExecute(t1 TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
+func (t *Table) onSessionQueryStreamExecute(t1 TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
fn := t.OnSessionQueryStreamExecute
if fn == nil {
- return func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
- return func(TableSessionQueryStreamExecuteDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamExecuteDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
- return func(TableSessionQueryStreamExecuteDoneInfo) {
- return
- }
- }
- }
- return func(t TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
- res := res(t)
- if res == nil {
- return func(TableSessionQueryStreamExecuteDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamExecuteDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onSessionQueryStreamRead(t1 TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
+func (t *Table) onSessionQueryStreamRead(t1 TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadDoneInfo) {
fn := t.OnSessionQueryStreamRead
if fn == nil {
- return func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
- return func(TableSessionQueryStreamReadDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamReadDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
- return func(TableSessionQueryStreamReadDoneInfo) {
- return
- }
- }
- }
- return func(t TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
- res := res(t)
- if res == nil {
- return func(TableSessionQueryStreamReadDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamReadDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onSessionTransactionBegin(t1 TableSessionTransactionBeginStartInfo) func(TableSessionTransactionBeginDoneInfo) {
- fn := t.OnSessionTransactionBegin
+func (t *Table) onTxBegin(t1 TableTxBeginStartInfo) func(TableTxBeginDoneInfo) {
+ fn := t.OnTxBegin
if fn == nil {
- return func(TableSessionTransactionBeginDoneInfo) {
+ return func(TableTxBeginDoneInfo) {
return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionTransactionBeginDoneInfo) {
+ return func(TableTxBeginDoneInfo) {
return
}
}
return res
}
-func (t *Table) onSessionTransactionExecute(t1 TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
- fn := t.OnSessionTransactionExecute
+func (t *Table) onTxExecute(t1 TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
+ fn := t.OnTxExecute
if fn == nil {
return func(TableTransactionExecuteDoneInfo) {
return
@@ -1309,8 +1099,8 @@ func (t *Table) onSessionTransactionExecute(t1 TableTransactionExecuteStartInfo)
}
return res
}
-func (t *Table) onSessionTransactionExecuteStatement(t1 TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
- fn := t.OnSessionTransactionExecuteStatement
+func (t *Table) onTxExecuteStatement(t1 TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
+ fn := t.OnTxExecuteStatement
if fn == nil {
return func(TableTransactionExecuteStatementDoneInfo) {
return
@@ -1324,31 +1114,31 @@ func (t *Table) onSessionTransactionExecuteStatement(t1 TableTransactionExecuteS
}
return res
}
-func (t *Table) onSessionTransactionCommit(t1 TableSessionTransactionCommitStartInfo) func(TableSessionTransactionCommitDoneInfo) {
- fn := t.OnSessionTransactionCommit
+func (t *Table) onTxCommit(t1 TableTxCommitStartInfo) func(TableTxCommitDoneInfo) {
+ fn := t.OnTxCommit
if fn == nil {
- return func(TableSessionTransactionCommitDoneInfo) {
+ return func(TableTxCommitDoneInfo) {
return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionTransactionCommitDoneInfo) {
+ return func(TableTxCommitDoneInfo) {
return
}
}
return res
}
-func (t *Table) onSessionTransactionRollback(t1 TableSessionTransactionRollbackStartInfo) func(TableSessionTransactionRollbackDoneInfo) {
- fn := t.OnSessionTransactionRollback
+func (t *Table) onTxRollback(t1 TableTxRollbackStartInfo) func(TableTxRollbackDoneInfo) {
+ fn := t.OnTxRollback
if fn == nil {
- return func(TableSessionTransactionRollbackDoneInfo) {
+ return func(TableTxRollbackDoneInfo) {
return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionTransactionRollbackDoneInfo) {
+ return func(TableTxRollbackDoneInfo) {
return
}
}
@@ -1375,36 +1165,6 @@ func (t *Table) onPoolSessionRemove(info TablePoolSessionRemoveInfo) {
}
fn(info)
}
-func (t *Table) onPoolSessionNew(t1 TablePoolSessionNewStartInfo) func(TablePoolSessionNewDoneInfo) {
- fn := t.OnPoolSessionNew
- if fn == nil {
- return func(TablePoolSessionNewDoneInfo) {
- return
- }
- }
- res := fn(t1)
- if res == nil {
- return func(TablePoolSessionNewDoneInfo) {
- return
- }
- }
- return res
-}
-func (t *Table) onPoolSessionClose(t1 TablePoolSessionCloseStartInfo) func(TablePoolSessionCloseDoneInfo) {
- fn := t.OnPoolSessionClose
- if fn == nil {
- return func(TablePoolSessionCloseDoneInfo) {
- return
- }
- }
- res := fn(t1)
- if res == nil {
- return func(TablePoolSessionCloseDoneInfo) {
- return
- }
- }
- return res
-}
func (t *Table) onPoolPut(t1 TablePoolPutStartInfo) func(TablePoolPutDoneInfo) {
fn := t.OnPoolPut
if fn == nil {
@@ -1450,15 +1210,14 @@ func (t *Table) onPoolWait(t1 TablePoolWaitStartInfo) func(TablePoolWaitDoneInfo
}
return res
}
-func TableOnInit(t *Table, c *context.Context, call call) func(limit int, _ error) {
+func TableOnInit(t *Table, c *context.Context, call call) func(limit int) {
var p TableInitStartInfo
p.Context = c
p.Call = call
res := t.onInit(p)
- return func(limit int, e error) {
+ return func(limit int) {
var p TableInitDoneInfo
p.Limit = limit
- p.Error = e
res(p)
}
}
@@ -1473,64 +1232,47 @@ func TableOnClose(t *Table, c *context.Context, call call) func(error) {
res(p)
}
}
-func TableOnDo(t *Table, c *context.Context, call call, iD string, label string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) {
+func TableOnDo(t *Table, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(attempts int, _ error) {
var p TableDoStartInfo
p.Context = c
p.Call = call
- p.ID = iD
p.Label = label
p.Idempotent = idempotent
p.NestedCall = nestedCall
res := t.onDo(p)
- return func(e error) func(int, error) {
- var p TableDoIntermediateInfo
+ return func(attempts int, e error) {
+ var p TableDoDoneInfo
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(attempts int, e error) {
- var p TableDoDoneInfo
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnDoTx(t *Table, c *context.Context, call call, iD string, label string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) {
+func TableOnDoTx(t *Table, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(attempts int, _ error) {
var p TableDoTxStartInfo
p.Context = c
p.Call = call
- p.ID = iD
p.Label = label
p.Idempotent = idempotent
p.NestedCall = nestedCall
res := t.onDoTx(p)
- return func(e error) func(int, error) {
- var p TableDoTxIntermediateInfo
+ return func(attempts int, e error) {
+ var p TableDoTxDoneInfo
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(attempts int, e error) {
- var p TableDoTxDoneInfo
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnCreateSession(t *Table, c *context.Context, call call) func(error) func(session tableSessionInfo, attempts int, _ error) {
+func TableOnCreateSession(t *Table, c *context.Context, call call) func(session tableSessionInfo, attempts int, _ error) {
var p TableCreateSessionStartInfo
p.Context = c
p.Call = call
res := t.onCreateSession(p)
- return func(e error) func(tableSessionInfo, int, error) {
- var p TableCreateSessionIntermediateInfo
+ return func(session tableSessionInfo, attempts int, e error) {
+ var p TableCreateSessionDoneInfo
+ p.Session = session
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(session tableSessionInfo, attempts int, e error) {
- var p TableCreateSessionDoneInfo
- p.Session = session
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
func TableOnSessionNew(t *Table, c *context.Context, call call) func(session tableSessionInfo, _ error) {
@@ -1628,7 +1370,7 @@ func TableOnSessionQueryExplain(t *Table, c *context.Context, call call, session
res(p)
}
}
-func TableOnSessionQueryStreamExecute(t *Table, c *context.Context, call call, session tableSessionInfo, query tableDataQuery, parameters tableQueryParameters) func(error) func(error) {
+func TableOnSessionQueryStreamExecute(t *Table, c *context.Context, call call, session tableSessionInfo, query tableDataQuery, parameters tableQueryParameters) func(error) {
var p TableSessionQueryStreamExecuteStartInfo
p.Context = c
p.Call = call
@@ -1636,48 +1378,38 @@ func TableOnSessionQueryStreamExecute(t *Table, c *context.Context, call call, s
p.Query = query
p.Parameters = parameters
res := t.onSessionQueryStreamExecute(p)
- return func(e error) func(error) {
- var p TableSessionQueryStreamExecuteIntermediateInfo
+ return func(e error) {
+ var p TableSessionQueryStreamExecuteDoneInfo
p.Error = e
- res := res(p)
- return func(e error) {
- var p TableSessionQueryStreamExecuteDoneInfo
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnSessionQueryStreamRead(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) func(error) {
+func TableOnSessionQueryStreamRead(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TableSessionQueryStreamReadStartInfo
p.Context = c
p.Call = call
p.Session = session
res := t.onSessionQueryStreamRead(p)
- return func(e error) func(error) {
- var p TableSessionQueryStreamReadIntermediateInfo
+ return func(e error) {
+ var p TableSessionQueryStreamReadDoneInfo
p.Error = e
- res := res(p)
- return func(e error) {
- var p TableSessionQueryStreamReadDoneInfo
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnSessionTransactionBegin(t *Table, c *context.Context, call call, session tableSessionInfo) func(tx tableTransactionInfo, _ error) {
- var p TableSessionTransactionBeginStartInfo
+func TableOnTxBegin(t *Table, c *context.Context, call call, session tableSessionInfo) func(tx tableTransactionInfo, _ error) {
+ var p TableTxBeginStartInfo
p.Context = c
p.Call = call
p.Session = session
- res := t.onSessionTransactionBegin(p)
+ res := t.onTxBegin(p)
return func(tx tableTransactionInfo, e error) {
- var p TableSessionTransactionBeginDoneInfo
+ var p TableTxBeginDoneInfo
p.Tx = tx
p.Error = e
res(p)
}
}
-func TableOnSessionTransactionExecute(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, query tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
+func TableOnTxExecute(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, query tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
var p TableTransactionExecuteStartInfo
p.Context = c
p.Call = call
@@ -1685,7 +1417,7 @@ func TableOnSessionTransactionExecute(t *Table, c *context.Context, call call, s
p.Tx = tx
p.Query = query
p.Parameters = parameters
- res := t.onSessionTransactionExecute(p)
+ res := t.onTxExecute(p)
return func(result tableResult, e error) {
var p TableTransactionExecuteDoneInfo
p.Result = result
@@ -1693,7 +1425,7 @@ func TableOnSessionTransactionExecute(t *Table, c *context.Context, call call, s
res(p)
}
}
-func TableOnSessionTransactionExecuteStatement(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, statementQuery tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
+func TableOnTxExecuteStatement(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, statementQuery tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
var p TableTransactionExecuteStatementStartInfo
p.Context = c
p.Call = call
@@ -1701,7 +1433,7 @@ func TableOnSessionTransactionExecuteStatement(t *Table, c *context.Context, cal
p.Tx = tx
p.StatementQuery = statementQuery
p.Parameters = parameters
- res := t.onSessionTransactionExecuteStatement(p)
+ res := t.onTxExecuteStatement(p)
return func(result tableResult, e error) {
var p TableTransactionExecuteStatementDoneInfo
p.Result = result
@@ -1709,28 +1441,28 @@ func TableOnSessionTransactionExecuteStatement(t *Table, c *context.Context, cal
res(p)
}
}
-func TableOnSessionTransactionCommit(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
- var p TableSessionTransactionCommitStartInfo
+func TableOnTxCommit(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
+ var p TableTxCommitStartInfo
p.Context = c
p.Call = call
p.Session = session
p.Tx = tx
- res := t.onSessionTransactionCommit(p)
+ res := t.onTxCommit(p)
return func(e error) {
- var p TableSessionTransactionCommitDoneInfo
+ var p TableTxCommitDoneInfo
p.Error = e
res(p)
}
}
-func TableOnSessionTransactionRollback(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
- var p TableSessionTransactionRollbackStartInfo
+func TableOnTxRollback(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
+ var p TableTxRollbackStartInfo
p.Context = c
p.Call = call
p.Session = session
p.Tx = tx
- res := t.onSessionTransactionRollback(p)
+ res := t.onTxRollback(p)
return func(e error) {
- var p TableSessionTransactionRollbackDoneInfo
+ var p TableTxRollbackDoneInfo
p.Error = e
res(p)
}
@@ -1751,29 +1483,6 @@ func TableOnPoolSessionRemove(t *Table, session tableSessionInfo) {
p.Session = session
t.onPoolSessionRemove(p)
}
-func TableOnPoolSessionNew(t *Table, c *context.Context, call call) func(session tableSessionInfo, _ error) {
- var p TablePoolSessionNewStartInfo
- p.Context = c
- p.Call = call
- res := t.onPoolSessionNew(p)
- return func(session tableSessionInfo, e error) {
- var p TablePoolSessionNewDoneInfo
- p.Session = session
- p.Error = e
- res(p)
- }
-}
-func TableOnPoolSessionClose(t *Table, c *context.Context, call call, session tableSessionInfo) func() {
- var p TablePoolSessionCloseStartInfo
- p.Context = c
- p.Call = call
- p.Session = session
- res := t.onPoolSessionClose(p)
- return func() {
- var p TablePoolSessionCloseDoneInfo
- res(p)
- }
-}
func TableOnPoolPut(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TablePoolPutStartInfo
p.Context = c
diff --git a/trace/trace_test.go b/trace/trace_test.go
index 6cb8a5b1b..fbdf19668 100644
--- a/trace/trace_test.go
+++ b/trace/trace_test.go
@@ -69,6 +69,7 @@ func stubEachFunc(x reflect.Value) map[string]bool {
fs[name] = true
},
}).Stub(x)
+
return fs
}
diff --git a/trace/traceutil.go b/trace/traceutil.go
index 613e0b237..8ad52bfb6 100644
--- a/trace/traceutil.go
+++ b/trace/traceutil.go
@@ -23,6 +23,7 @@ func ClearContext(x interface{}) interface{} {
c.Set(reflect.Zero(c.Type()))
p.Set(x)
}
+
return p.Interface()
}
@@ -69,6 +70,7 @@ func (f FieldStubber) Stub(x reflect.Value) {
params[i] = arg.Interface()
}
f.OnCall(name, params...)
+
return out
})
fx.Set(fn)
diff --git a/with.go b/with.go
index f8a39d594..c226db991 100644
--- a/with.go
+++ b/with.go
@@ -2,14 +2,14 @@ package ydb
import (
"context"
+ "sync/atomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xatomic"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
-var nextID xatomic.Uint64 //nolint:gochecknoglobals
+var nextID atomic.Uint64 //nolint:gochecknoglobals
func (d *Driver) with(ctx context.Context, opts ...Option) (*Driver, uint64, error) {
id := nextID.Add(1)
@@ -49,7 +49,7 @@ func (d *Driver) With(ctx context.Context, opts ...Option) (*Driver, error) {
onDone := trace.DriverOnWith(
d.trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.(*Driver).With"),
d.config.Endpoint(), d.config.Database(), d.config.Secure(),
)
defer func() {