App in Go

This page contains a detailed description of the code of a test app that uses the YDB Go SDK.

Downloading and starting

The startup script given below uses git and Go. Be sure to install the YDB Go SDK first.

Create a working directory and use it to run from the command line the command to clone the GitHub repository:

  1. git clone https://github.com/ydb-platform/ydb-go-examples/

Go - 图1

Next, from the same working directory, run the command to start the test app. The command will differ depending on the database to connect to.

Local Docker

Any database

To connect to a locally deployed YDB database according to the Docker use case, run the following command in the default configuration:

  1. ( export YDB_ANONYMOUS_CREDENTIALS=1 && cd ydb-go-examples && \
  2. go run ./basic -ydb="grpc://localhost:2136?database=/local" )

Go - 图2

To run the example using any available YDB database, you need to know the Endpoint and Database location.

If authentication is enabled in the database, you also need to choose the authentication mode and obtain secrets: a token or username/password.

Run the command as follows:

  1. ( export <auth_mode_var>="<auth_mode_value>" && cd ydb-go-examples && \
  2. go run ./basic -ydb="<endpoint>?database=<database>" )

Go - 图3

, where

  • <endpoint> is the Endpoint
  • <database> is the DB location.
  • <auth_mode_var> is the Environment variable that determines the authentication mode.
  • <auth_mode_value> is the authentication parameter value for the selected mode.

For example:

  1. ( export YDB_ACCESS_TOKEN_CREDENTIALS="t1.9euelZqOnJuJlc..." && cd ydb-go-examples && \
  2. go run ./basic -ydb="grpcs://ydb.example.com:2135?database=/somepath/somelocation" )

Go - 图4

Note

If you previously reviewed the articles of the “Getting started” section, you must have used the necessary parameters when getting started with the YDB CLI and can get them from the profile:

  1. ydb config profile get db1

Go - 图5

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/ydb-platform/ydb-go-sdk/v3"
  7. "github.com/ydb-platform/ydb-go-sdk/v3/table" // to work with the table service
  8. "github.com/ydb-platform/ydb-go-sdk/v3/table/options" // to work with the table service
  9. "github.com/ydb-platform/ydb-go-sdk/v3/table/result" // to work with the table service
  10. "github.com/ydb-platform/ydb-go-sdk/v3/table/result/named" // to work with the table service
  11. "github.com/ydb-platform/ydb-go-sdk-auth-environ" // for authentication using environment variables
  12. "github.com/ydb-platform/ydb-go-yc" // to work with YDB in Yandex.Cloud
  13. )

Go - 图6

App code snippet for driver initialization:

  1. ctx := context.Background()
  2. // connection string
  3. dsn := "grpcs://ydb.serverless.yandexcloud.net:2135/?database=/ru-central1/b1g8skpblkos03malf3s/etn01f8gv9an9sedo9fu"
  4. // IAM token
  5. token := "t1.9euelZrOy8aVmZKJm5HGjceMkMeVj-..."
  6. // creating a DB connection object, which is the input point for YDB services
  7. db, err := ydb.Open(
  8. ctx,
  9. dsn,
  10. // yc.WithInternalCA(), // using Yandex.Cloud certificates
  11. ydb.WithAccessTokenCredentials(token), // token-based authentication
  12. // ydb.WithAnonimousCredentials(token), // anonymous authentication (for example, in docker ydb)
  13. // yc.WithMetadataCredentials(token), // authentication from inside a VM in Yandex.Cloud or a function in Yandex Functions
  14. // yc.WithServiceAccountKeyFileCredentials("~/.ydb/sa.json"), // authentication in Yandex.Cloud using a service account file
  15. // environ.WithEnvironCredentials(ctx), // authentication using environment variables
  16. )
  17. if err != nil {
  18. // connection error handling
  19. }
  20. // closing the driver at the end of the program is mandatory
  21. defer func() {
  22. _ = db.Close(ctx)
  23. }

Go - 图7

The db object is an input point for working with YDB services.
To work with the table service, use the db.Table() client.
The client of the table service provides an API for making queries to tables.
The most popular method is db.Table().Do(ctx, op). It implements background session creation and repeated attempts to perform the op user operation where the created session is passed to the user-defined code.
The session has an exhaustive API that lets you perform DDL, DML, DQL, and TCL requests.

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 table.Session.CreateTable() method:

  1. err = db.Table().Do(
  2. ctx,
  3. func(ctx context.Context, s table.Session) (err error) {
  4. return s.CreateTable(ctx, path.Join(db.Name(), "series"),
  5. options.WithColumn("series_id", types.Optional(types.TypeUint64)),
  6. options.WithColumn("title", types.Optional(types.TypeUTF8)),
  7. options.WithColumn("series_info", types.Optional(types.TypeUTF8)),
  8. options.WithColumn("release_date", types.Optional(types.TypeDate)),
  9. options.WithColumn("comment", types.Optional(types.TypeUTF8)),
  10. options.WithPrimaryKeyColumn("series_id"),
  11. )
  12. },
  13. )
  14. if err != nil {
  15. // handling the situation when the request failed
  16. }

Go - 图8

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

  1. err = db.Table().Do(
  2. ctx,
  3. func(ctx context.Context, s table.Session) (err error) {
  4. desc, err := s.DescribeTable(ctx, path.Join(db.Name(), "series"))
  5. if err != nil {
  6. return
  7. }
  8. log.Printf("> describe table: %s\n", tableName)
  9. for _, c := range desc.Columns {
  10. log.Printf(" > column, name: %s, %s\n", c.Type, c.Name)
  11. }
  12. return
  13. }
  14. )
  15. if err != nil {
  16. // handling the situation when the request failed
  17. }

Go - 图9

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 table.Session.Execute() method.
The SDK lets you explicitly control the execution of transactions and configure the transaction execution mode using the table.TxControl structure.

  1. var (
  2. readTx = table.TxControl(
  3. table.BeginTx(
  4. table.WithOnlineReadOnly(),
  5. ),
  6. table.CommitTx(),
  7. )
  8. )
  9. err := db.Table().Do(
  10. ctx,
  11. func(ctx context.Context, s table.Session) (err error) {
  12. var (
  13. res result.Result
  14. id *uint64 // pointer - for optional results
  15. title *string // pointer - for optional results
  16. date *time.Time // pointer - for optional results
  17. )
  18. _, res, err = s.Execute(
  19. ctx,
  20. readTx,
  21. `
  22. DECLARE $seriesID AS Uint64;
  23. SELECT
  24. series_id,
  25. title,
  26. release_date
  27. FROM
  28. series
  29. WHERE
  30. series_id = $seriesID;
  31. `,
  32. table.NewQueryParameters(
  33. table.ValueParam("$seriesID", types.Uint64Value(1)), // substitution in the query condition
  34. ),
  35. options.WithQueryCachePolicy(
  36. options.WithQueryCachePolicyKeepInCache(), // enabling the server cache of compiled queries
  37. ),
  38. )
  39. if err != nil {
  40. return err
  41. }
  42. defer func() {
  43. _ = res.Close() // making sure the result is closed
  44. }()
  45. log.Printf("> select_simple_transaction:\n")
  46. for res.NextResultSet(ctx) {
  47. for res.NextRow() {
  48. // passing column names from the scanning line to ScanNamed,
  49. // addresses (and data types) to assign query results to
  50. err = res.ScanNamed(
  51. named.Optional("series_id", &id),
  52. named.Optional("title", &title),
  53. named.Optional("release_date", &date),
  54. )
  55. if err != nil {
  56. return err
  57. }
  58. log.Printf(
  59. " > %d %s %s\n",
  60. *id, *title, *date,
  61. )
  62. }
  63. }
  64. return res.Err()
  65. },
  66. )
  67. if err != nil {
  68. // handling the query execution error
  69. }

Go - 图10

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.

To execute scan queries, use the table.Session.StreamExecuteScanQuery() method.

  1. var (
  2. query = `
  3. DECLARE $series AS List<UInt64>;
  4. SELECT series_id, season_id, title, first_aired
  5. FROM seasons
  6. WHERE series_id IN $series
  7. `
  8. res result.StreamResult
  9. )
  10. err = c.Do(
  11. ctx,
  12. func(ctx context.Context, s table.Session) (err error) {
  13. res, err = s.StreamExecuteScanQuery(ctx, query,
  14. table.NewQueryParameters(
  15. table.ValueParam("$series",
  16. types.ListValue(
  17. types.Uint64Value(1),
  18. types.Uint64Value(10),
  19. ),
  20. ),
  21. ),
  22. )
  23. if err != nil {
  24. return err
  25. }
  26. defer func() {
  27. _ = res.Close() // making sure the result is closed
  28. }()
  29. var (
  30. seriesID uint64
  31. seasonID uint64
  32. title string
  33. date time.Time
  34. )
  35. log.Print("\n> scan_query_select:")
  36. for res.NextResultSet(ctx) {
  37. if err = res.Err(); err != nil {
  38. return err
  39. }
  40. for res.NextRow() {
  41. // named.OptionalOrDefault lets you "deploy" optional
  42. // results or use the default value of the go type
  43. err = res.ScanNamed(
  44. named.OptionalOrDefault("series_id", &seriesID),
  45. named.OptionalOrDefault("season_id", &seasonID),
  46. named.OptionalOrDefault("title", &title),
  47. named.OptionalOrDefault("first_aired", &date),
  48. )
  49. if err != nil {
  50. return err
  51. }
  52. log.Printf("# Season, SeriesId: %d, SeasonId: %d, Title: %s, Air date: %s", seriesID, seasonID, title, date)
  53. }
  54. }
  55. return res.Err()
  56. },
  57. )
  58. if err != nil {
  59. // handling the query execution error
  60. }

Go - 图11

Note

Sample code of a test app that uses archived of versions the Go SDK: