github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/MIGRATION_v2_v3.md (about) 1 # Migration from `ydb-go-sdk/v2` to `ydb-go-sdk/v3` 2 3 > Article contains some cases for migrate from `github.com/yandex-cloud/ydb-go-sdk/v2` to `github.com/ydb-platform/ydb-go-sdk/v3` 4 5 ## Table of contents 6 1. [Imports](#imports) 7 2. [Connect to `YDB` by `endpoint` and `database`](#connect) 8 3. [Connect to `YDB` using connection string](#connect-dsn) 9 4. [Make table client and session pool](#table-client) 10 5. [Execute query with table client and session pool](#execute-queries) 11 6. [About truncated result](#truncated) 12 7. [Scan query result into local variables](#scan-result) 13 8. [Logging SDK's events](#logs) 14 9. [Add metrics about SDK's events](#metrics) 15 10. [Add `Jaeger` traces about SDK's events](#jaeger) 16 17 ## Imports <a name="imports"></a> 18 - in `v2`: 19 ``` 20 "github.com/yandex-cloud/ydb-go-sdk/v2" 21 "github.com/yandex-cloud/ydb-go-sdk/v2/table" 22 ``` 23 - in `v3`: 24 ``` 25 "github.com/ydb-platform/ydb-go-sdk/v3" 26 "github.com/ydb-platform/ydb-go-sdk/v3/table" 27 ``` 28 29 ## Connect to `YDB` by `endpoint` and `database` <a name="connect"></a> 30 - in `v2`: 31 ```go 32 config := &ydb.DriverConfig{ 33 Database: cfg.Database, 34 } 35 driver, err := (&ydb.Dialer{ 36 DriverConfig: config, 37 }).Dial(ctx, cfg.Addr) 38 if err != nil { 39 // error fallback 40 } 41 defer func() { 42 _ = driver.Close() 43 }() 44 ``` 45 - in `v3`: 46 ```go 47 import ( 48 "github.com/ydb-platform/ydb-go-sdk/v3/sugar" 49 ) 50 ... 51 db, err := ydb.Open(ctx, 52 sugar.DSN(cfg.Endpoint, cfg.Database, cfg.Secure) 53 ) 54 if err != nil { 55 // error fallback 56 } 57 defer func() { 58 _ = db.Close(ctx) 59 }() 60 ``` 61 62 ## Connect to `YDB` using connection string <a name="connect-dsn"></a> 63 - in `v2`: 64 ```go 65 import ( 66 "github.com/yandex-cloud/ydb-go-sdk/v2/connect" 67 ) 68 ... 69 params, err := connect.ConnectionString("grpc://ydb-ru.yandex.net:2135/?database=/ru/home/my/db") 70 if err != nil { 71 // error fallback 72 } 73 ... 74 config.Database = params.Database() 75 ... 76 driver, err := (&ydb.Dialer{ 77 DriverConfig: config, 78 }).Dial(ctx, params.Endpoint()) 79 ``` 80 - in `v3`: 81 ```go 82 db, err := ydb.Open(ctx, 83 "grpc://ydb-ru.yandex.net:2135/ru/home/my/db", 84 ) 85 if err != nil { 86 // error fallback 87 } 88 defer func() { 89 _ = db.Close(ctx) 90 }() 91 ``` 92 93 ## Make table client and session pool <a name="table-client"></a> 94 - in `v2`: 95 ```go 96 import ( 97 "github.com/yandex-cloud/ydb-go-sdk/v2/table" 98 ) 99 ... 100 tableClient := &table.Client{ 101 Driver: driver, 102 } 103 sp := &table.SessionPool{ 104 Builder: tableClient, 105 } 106 defer func() { 107 _ = sp.Close(ctx) 108 }() 109 ``` 110 - in `v3`: nothing to do, table client with internal session pool always available with `db.Table()` 111 112 ## Execute query with table client and session pool <a name="execute-queries"></a> 113 - in `v2`: 114 ```go 115 var res *table.Result 116 err := table.Retry(ctx, sp, 117 table.OperationFunc( 118 func(ctx context.Context, s *table.Session) (err error) { 119 _, res, err = s.Execute(ctx, readTx, "SELECT 1+1") 120 return err 121 }, 122 ) 123 ) 124 if err != nil { 125 // error fallback 126 } 127 ``` 128 - in `v3`: 129 ```go 130 import ( 131 "github.com/ydb-platform/ydb-go-sdk/v3/table/result" 132 ) 133 ... 134 var res result.Result 135 err := db.Table().Do(ctx, 136 func(ctx context.Context, s table.Session) (err error) { 137 _, res, err = s.Execute(ctx, readTx, "SELECT 1+1") 138 return err 139 }, 140 table.WithIdempotent(), // only idempotent queries 141 ) 142 if err != nil { 143 // error fallback 144 } 145 ``` 146 147 ## About truncated result <a name="truncated"></a> 148 149 Call of `session.Execute` may return a result with a flag `Truncated` because `YDB` have a default limit of rows is a 1000. 150 In this case query must be changed for supporting pagination. Truncated flag in result must be checks explicitly. 151 - in `v2`: 152 ```go 153 var res *table.Result 154 err := table.Retry(ctx, sp, 155 table.OperationFunc( 156 func(ctx context.Context, s *table.Session) (err error) { 157 _, res, err = s.Execute(ctx, readTx, "SELECT 1+1") 158 if err != nil { 159 // error fallback 160 } 161 for res.NextStreamSet(ctx) { 162 for res.NextRow() { 163 // process column values 164 } 165 } 166 if err := res.Err(); err != nil { 167 // error fallback 168 } 169 if res.Trucated() { 170 // alarm to query developers 171 } 172 return nil 173 }, 174 ), 175 } 176 if err != nil { 177 // error fallback 178 } 179 ``` 180 - in `v3`: 181 By default, truncated result wraps as non-retryable error for `session.Execute` and retryable error for `session.StreamExecuteScanQuery` 182 ```go 183 import ( 184 "github.com/ydb-platform/ydb-go-sdk/v3/table/result" 185 ) 186 ... 187 var res result.Result 188 err := db.Table().Do(ctx, 189 func(ctx context.Context, s table.Session) (err error) { 190 _, res, err = s.Execute(ctx, readTx, "SELECT 1+1") 191 if err != nil { 192 // error fallback 193 } 194 for res.NextStreamSet(ctx) { 195 for res.NextRow() { 196 // process column values 197 } 198 } 199 // no need to check truncated result explicitly 200 // if res.Truncated() { 201 // // alarm to query developers 202 // } 203 return res.Err() 204 }, 205 table.WithIdempotent(), // only idempotent queries 206 ) 207 if err != nil { 208 // error fallback 209 } 210 ``` 211 But if default behaviour are not allowed, wrapping truncated result as error may be disabled with option `ydb.WithIgnoreTruncated` 212 213 214 ## Scan query result into local variables <a name="scan-result"></a> 215 - in `v2`: 216 ```go 217 var ( 218 id uint64 219 title string 220 date uint64 221 description string 222 duration uint64 223 ) 224 for res.NextStreamSet(ctx) { 225 for res.NextRow() { 226 res.SeekItem("series_id") 227 id = res.OUint64() 228 229 res.SeekItem("title") 230 title = res.OUTF8() 231 232 res.SeekItem("release_date") 233 date = res.OUint64() 234 235 res.SeekItem("description") 236 description = res.OUTF8() 237 238 res.SeekItem("duration") 239 duration = res.OUint64() 240 241 log.Printf("# %d %s %s %s %v", 242 id, title, time.UnixMilli(date).Format("02/01/2006, 15:04:05"), 243 description, time.Duration(duration) * time.Millisecond, 244 ) 245 } 246 } 247 if err := res.Err(); err != nil { 248 // error fallback 249 } 250 ``` 251 - in `v3`: 252 ```go 253 import ( 254 "github.com/ydb-platform/ydb-go-sdk/v3/table/result/named" 255 ) 256 ... 257 var ( 258 id uint64 259 title *string 260 date *time.Time 261 description *string 262 duration time.Duration 263 ) 264 for res.NextResultSet(ctx) { 265 for res.NextRow() { 266 err := res.ScanNamed( 267 named.Required("series_id", &id), 268 named.Optional("title", &title), 269 named.Optional("release_date", &date), 270 named.Optional("description", &description), 271 named.OptionalWithDefault("duration", &duration), 272 ) 273 if err != nil { 274 // error fallback 275 } 276 log.Printf("# %d %s %s %s %v", 277 id, title, date.Format("02/01/2006, 15:04:05"), 278 description, duration, 279 ) 280 } 281 } 282 if err := res.Err(); err != nil { 283 // error fallback 284 } 285 ``` 286 287 ## Logging SDK's events <a name="logs"></a> 288 - in `v2`: 289 ```go 290 config.Trace = ydb.DriverTrace{ 291 OnDial: func(info ydb.DialStartInfo) func(info ydb.DialDoneInfo) { 292 address := info.Address 293 fmt.Printf(`dial start {address:"%s"}`, address) 294 start := time.Now() 295 return func(info ydb.DialDoneInfo) { 296 if info.Error == nil { 297 fmt.Printf(`dial done {latency:"%s",address:"%s"}`, time.Since(start), address) 298 } else { 299 fmt.Printf(`dial failed {latency:"%s",address:"%s",error:"%s"}`, time.Since(start), address, info.Error) 300 } 301 } 302 }, 303 // ... and more callbacks of ydb.DriverTrace need to define 304 } 305 sp.Trace = table.Trace{ 306 // must callbacks of table.Trace 307 } 308 ``` 309 - in `v3`: 310 * `ydb-go-sdk/v3` contains internal logger, which may to enable with env `YDB_LOG_SEVERITY_LEVEL=info` 311 * external `zap` logger: 312 ```go 313 import ydbZap "github.com/ydb-platform/ydb-go-sdk-zap" 314 ... 315 db, err := ydb.Open(ctx, connectionString, 316 ... 317 ydbZap.WithTraces(log, trace.DetailsAll), 318 ) 319 ``` 320 * external `zerolog` logger: 321 ```go 322 import ydbZerolog "github.com/ydb-platform/ydb-go-sdk-zerolog" 323 ... 324 db, err := ydb.Open(ctx, connectionString, 325 ... 326 ydbZerolog.WithTraces(log, trace.DetailsAll), 327 ) 328 ``` 329 330 ## Add metrics about SDK's events <a name="metrics"></a> 331 - in `v2`: 332 ```go 333 config.Trace = ydb.DriverTrace{ 334 // must define callbacks of ydb.DriverTrace 335 } 336 sp.Trace = table.Trace{ 337 // must define callbacks of table.Trace 338 } 339 ``` 340 - in `v3`: 341 * metrics into `Prometheus` system 342 ```go 343 import ( 344 ydbMetrics "github.com/ydb-platform/ydb-go-sdk-prometheus" 345 ) 346 ... 347 registry := prometheus.NewRegistry() 348 db, err := ydb.Open(ctx, connectionString, 349 ... 350 ydbMetrics.WithTraces(registry, ydbMetrics.WithDetails(trace.DetailsAll)), 351 ) 352 ``` 353 * metrics to other monitoring systems may be add with common package `"github.com/ydb-platform/ydb-go-sdk-metrics"` 354 355 ## Add `Jaeger` traces about SDK's events <a name="jaeger"></a> 356 - in `v2`: 357 ```go 358 config.Trace = ydb.DriverTrace{ 359 // must define callbacks of ydb.DriverTrace 360 } 361 sp.Trace = table.Trace{ 362 // must define callbacks of table.Trace 363 } 364 ``` 365 - in `v3`: 366 ```go 367 import ( 368 ydbTracing "github.com/ydb-platform/ydb-go-sdk-opentracing" 369 ) 370 ... 371 db, err := ydb.Open(ctx, connectionString, 372 ... 373 ydbTracing.WithTraces(trace.DriverConnEvents | trace.DriverClusterEvents | trace.DriverRepeaterEvents | trace.DiscoveryEvents), 374 ) 375 ``` 376 377 See additional docs in [code recipes](https://ydb.tech/docs/reference/ydb-sdk/recipes/).