App in Go (archived version 2)

This page contains a detailed description of the code of a test app that is available as part of the v2 Go SDK YDB.

Initializing a database connection

To interact with YDB, create an instance of the driver, client, and session:

  • The YDB driver lets the app and YDB interact at the transport layer. The driver must exist throughout the YDB access lifecycle and be initialized before creating a client or session.
  • The YDB client runs on top of the YDB driver and enables the handling of entities and transactions.
  • The YDB session contains information about executed transactions and prepared queries, and is part of the YDB client context.

To work with YDB in Go, import the ydb-go-sdk driver package:

  1. import (
  2. // general imports
  3. "context"
  4. "path"
  5. // imports of ydb-go-sdk packages
  6. "github.com/yandex-cloud/ydb-go-sdk/v2"
  7. "github.com/yandex-cloud/ydb-go-sdk/v2/table" // to work with the table service
  8. )

Go v2 - 图1

App code snippet for driver initialization:

  1. func (cmd *Command) Run(ctx context.Context, params cli.Parameters) error {
  2. dialer := &ydb.Dialer{
  3. DriverConfig: cmd.config(params),
  4. TLSConfig: cmd.tls(),
  5. Timeout: time.Second,
  6. }
  7. driver, err := dialer.Dial(ctx, params.Endpoint)
  8. if err != nil {
  9. return fmt.Errorf("dial error: %v", err)
  10. }
  11. defer driver.Close()

Go v2 - 图2

App code snippet for creating a session:

  1. tableClient := table.Client{
  2. Driver: driver,
  3. }
  4. sp := table.SessionPool{
  5. IdleThreshold: time.Second,
  6. Builder: &tableClient,
  7. }
  8. defer sp.Close(ctx)

Go v2 - 图3

Creating tables

Creating tables to be used in operations on a test app. This step results in the creation of DB tables of the series directory data model:

  • Series
  • Seasons
  • Episodes

Once the tables are created, the method for getting information about data schema objects is called and the result of its execution is output.

To create tables, use the Session.CreateTable() method:

  1. func createTables(ctx context.Context, sp *table.SessionPool, prefix string) (err error) {
  2. err = table.Retry(ctx, sp,
  3. table.OperationFunc(func(ctx context.Context, s *table.Session) error {
  4. return s.CreateTable(ctx, path.Join(prefix, "series"),
  5. table.WithColumn("series_id", ydb.Optional(ydb.TypeUint64)),
  6. table.WithColumn("title", ydb.Optional(ydb.TypeUTF8)),
  7. table.WithColumn("series_info", ydb.Optional(ydb.TypeUTF8)),
  8. table.WithColumn("release_date", ydb.Optional(ydb.TypeUint64)),
  9. table.WithColumn("comment", ydb.Optional(ydb.TypeUTF8)),
  10. table.WithPrimaryKeyColumn("series_id"),
  11. )
  12. }),
  13. )

Go v2 - 图4

You can use the Session.DescribeTable() method to output information about the table structure and make sure that it was properly created:

  1. func describeTable(ctx context.Context, sp *table.SessionPool, path string) (err error) {
  2. err = table.Retry(ctx, sp,
  3. table.OperationFunc(func(ctx context.Context, s *table.Session) error {
  4. desc, err := s.DescribeTable(ctx, path)
  5. if err != nil {
  6. return err
  7. }
  8. log.Printf("\n> describe table: %s", path)
  9. for _, c := range desc.Columns {
  10. log.Printf("column, name: %s, %s", c.Type, c.Name)
  11. }
  12. return nil
  13. }),
  14. )

Go v2 - 图5

Retrieving data with a Select

Retrieving data using a SELECT statement in YQL. Handling the retrieved data selection in the app.

To execute YQL queries, use the Session.Execute() method.
The SDK lets you explicitly control the execution of transactions and configure the transaction execution mode using the TxControl class.

  1. var (
  2. query = `--!syntax_v1
  3. DECLARE $seriesID AS Uint64;
  4. $format = DateTime::Format("%Y-%m-%d");
  5. SELECT
  6. series_id,
  7. title,
  8. $format(DateTime::FromSeconds(CAST(DateTime::ToSeconds(DateTime::IntervalFromDays(CAST(release_date AS Int16))) AS Uint32))) AS release_date
  9. FROM
  10. series
  11. WHERE
  12. series_id = $seriesID;`
  13. res *table.Result
  14. )
  15. readTx := table.TxControl(
  16. table.BeginTx(
  17. table.WithOnlineReadOnly(),
  18. ),
  19. table.CommitTx(),
  20. )
  21. err = table.Retry(ctx, sp,
  22. table.OperationFunc(func(ctx context.Context, s *table.Session) (err error) {
  23. _, res, err = s.Execute(ctx, readTx, query,
  24. table.NewQueryParameters(
  25. table.ValueParam("$seriesID", ydb.Uint64Value(1)),
  26. ),
  27. table.WithQueryCachePolicy(
  28. table.WithQueryCachePolicyKeepInCache(),
  29. ),
  30. table.WithCollectStatsModeBasic(),
  31. )
  32. return
  33. }),
  34. )
  35. if err != nil {
  36. return err
  37. }

Go v2 - 图6

Processing execution results

Query results:

  1. var (
  2. id *uint64
  3. title *string
  4. date *[]byte
  5. )
  6. log.Println("> select_simple_transaction:")
  7. for res.NextResultSet(ctx, "series_id", "title", "release_date") {
  8. for res.NextRow() {
  9. err = res.Scan(&id, &title, &date)
  10. if err != nil {
  11. return err
  12. }
  13. log.Printf(
  14. "# SeriesID: %d , Title: %s, Date: %s\n",
  15. *id, *title, *date,
  16. )
  17. }
  18. }
  19. if err = res.Err(); err != nil {
  20. return err
  21. }
  22. return nil
  23. }

Go v2 - 图7

Scan queries

Making a scan query that results in a data stream. Streaming lets you read an unlimited number of rows and amount of data.

  1. var (
  2. query = `
  3. SELECT series_id, season_id, COUNT(*) AS episodes_count
  4. FROM episodes
  5. GROUP BY series_id, season_id
  6. ORDER BY series_id, season_id;`
  7. res *table.Result
  8. )
  9. err = table.Retry(ctx, sp,
  10. table.OperationFunc(func(ctx context.Context, s *table.Session) (err error) {
  11. res, err = s.StreamExecuteScanQuery(ctx, query, table.NewQueryParameters())
  12. return err
  13. }),
  14. )
  15. if err != nil {
  16. return err
  17. }

Go v2 - 图8

Scan queries

Making a scan query that results in a data stream. Streaming lets you read an unlimited number of rows and amount of data.

Query results:

  1. var (
  2. seriesID uint64
  3. seasonID uint64
  4. count uint64
  5. )
  6. log.Println("> scan_query_select:")
  7. for res.NextResultSet(ctx, "series_id", "season_id", "episodes_count") {
  8. for res.NextRow() {
  9. err = res.ScanWithDefaults(&seriesID, &seasonID, &count)
  10. if err != nil {
  11. return err
  12. }
  13. log.Printf("# Season, SeriesId: %d, SeasonId: %d, Count: %d\n", seriesID, seasonID, count)
  14. }
  15. }
  16. if err = res.Err(); err != nil {
  17. return err
  18. }
  19. return nil
  20. }

Go v2 - 图9

Handling errors

For more information about error handling, see Error handling in the API.