diff --git a/doc/code_snippets/snippets/connectors/go/README.md b/doc/code_snippets/snippets/connectors/go/README.md new file mode 100644 index 0000000000..fd3ca99a22 --- /dev/null +++ b/doc/code_snippets/snippets/connectors/go/README.md @@ -0,0 +1,14 @@ +# Go + +A sample application containing requests from the [Connecting from Go](https://www.tarantool.io/en/doc/latest/how-to/getting_started_go) tutorial. + + +## Running + +Before running this sample, start an application that allows remote connections to a sample database: [sample_db](../instances.enabled/sample_db). + +Then, start this sample by executing the following command in the `go` directory: + +``` +$ go run . +``` diff --git a/doc/code_snippets/snippets/connectors/go/go.mod b/doc/code_snippets/snippets/connectors/go/go.mod new file mode 100644 index 0000000000..191575428a --- /dev/null +++ b/doc/code_snippets/snippets/connectors/go/go.mod @@ -0,0 +1,12 @@ +module example/hello + +go 1.22.3 + +require ( + github.com/google/uuid v1.3.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/tarantool/go-iproto v1.0.0 // indirect + github.com/tarantool/go-tarantool/v2 v2.1.0 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect +) diff --git a/doc/code_snippets/snippets/connectors/go/go.sum b/doc/code_snippets/snippets/connectors/go/go.sum new file mode 100644 index 0000000000..199d48ec59 --- /dev/null +++ b/doc/code_snippets/snippets/connectors/go/go.sum @@ -0,0 +1,18 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tarantool/go-iproto v1.0.0 h1:quC4hdFhCuFYaCqOFgUxH2foRkhAy+TlEy7gQLhdVjw= +github.com/tarantool/go-iproto v1.0.0/go.mod h1:LNCtdyZxojUed8SbOiYHoc3v9NvaZTB7p96hUySMlIo= +github.com/tarantool/go-tarantool/v2 v2.1.0 h1:IY33WoS8Kqb+TxNnKbzu/7yVkiCNZGhbG5Gw0/tMfSk= +github.com/tarantool/go-tarantool/v2 v2.1.0/go.mod h1:cpjGW5FHAXIMf0PKZte70pMOeadw1MA/hrDv1LblWk4= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/doc/code_snippets/snippets/connectors/go/hello.go b/doc/code_snippets/snippets/connectors/go/hello.go new file mode 100644 index 0000000000..ee93e43def --- /dev/null +++ b/doc/code_snippets/snippets/connectors/go/hello.go @@ -0,0 +1,134 @@ +package main + +import ( + "context" + "fmt" + "github.com/tarantool/go-tarantool/v2" + _ "github.com/tarantool/go-tarantool/v2/datetime" + _ "github.com/tarantool/go-tarantool/v2/decimal" + _ "github.com/tarantool/go-tarantool/v2/uuid" + "time" +) + +func main() { + // Connect to the database + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + dialer := tarantool.NetDialer{ + Address: "127.0.0.1:3301", + User: "sampleuser", + Password: "123456", + } + opts := tarantool.Opts{ + Timeout: time.Second, + } + + conn, err := tarantool.Connect(ctx, dialer, opts) + if err != nil { + fmt.Println("Connection refused:", err) + return + } + + // Interact with the database + // ... + // Insert data + tuples := [][]interface{}{ + {1, "Roxette", 1986}, + {2, "Scorpions", 1965}, + {3, "Ace of Base", 1987}, + {4, "The Beatles", 1960}, + } + var futures []*tarantool.Future + for _, tuple := range tuples { + request := tarantool.NewInsertRequest("bands").Tuple(tuple) + futures = append(futures, conn.Do(request)) + } + fmt.Println("Inserted tuples:") + for _, future := range futures { + result, err := future.Get() + if err != nil { + fmt.Println("Got an error:", err) + } else { + fmt.Println(result) + } + } + + // Select by primary key + data, err := conn.Do( + tarantool.NewSelectRequest("bands"). + Limit(10). + Iterator(tarantool.IterEq). + Key([]interface{}{uint(1)}), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + fmt.Println("Tuple selected by the primary key value:", data) + + // Select by secondary key + data, err = conn.Do( + tarantool.NewSelectRequest("bands"). + Index("band"). + Limit(10). + Iterator(tarantool.IterEq). + Key([]interface{}{"The Beatles"}), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + fmt.Println("Tuple selected by the secondary key value:", data) + + // Update + data, err = conn.Do( + tarantool.NewUpdateRequest("bands"). + Key(tarantool.IntKey{2}). + Operations(tarantool.NewOperations().Assign(1, "Pink Floyd")), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + fmt.Println("Updated tuple:", data) + + // Upsert + data, err = conn.Do( + tarantool.NewUpsertRequest("bands"). + Tuple([]interface{}{uint(5), "The Rolling Stones", 1962}). + Operations(tarantool.NewOperations().Assign(1, "The Doors")), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + + // Replace + data, err = conn.Do( + tarantool.NewReplaceRequest("bands"). + Tuple([]interface{}{1, "Queen", 1970}), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + fmt.Println("Replaced tuple:", data) + + // Delete + data, err = conn.Do( + tarantool.NewDeleteRequest("bands"). + Key([]interface{}{uint(5)}), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + fmt.Println("Deleted tuple:", data) + + // Call + data, err = conn.Do( + tarantool.NewCallRequest("get_bands_older_than").Args([]interface{}{1966}), + ).Get() + if err != nil { + fmt.Println("Got an error:", err) + } + fmt.Println("Stored procedure result:", data) + + // Close connection + conn.CloseGraceful() + fmt.Println("Connection is closed") +} diff --git a/doc/how-to/getting_started_go.rst b/doc/how-to/getting_started_go.rst index 63b1169ba0..4398f52596 100644 --- a/doc/how-to/getting_started_go.rst +++ b/doc/how-to/getting_started_go.rst @@ -1,256 +1,279 @@ .. _getting_started-go: --------------------------------------------------------------------------------- Connecting from Go --------------------------------------------------------------------------------- +================== -.. _getting_started-go-pre-requisites: +**Examples on GitHub**: `sample_db `_, `go `_ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pre-requisites -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The tutorial shows how to use the `go-tarantool `__ 2.x library to create a Go application that connects to a remote Tarantool instance, performs CRUD operations, and executes a stored procedure. +You can find the full package documentation here: `Client in Go for Tarantool `__. -Before we proceed: -#. `Install `__ - the ``go-tarantool`` library. -#. :ref:`Start ` Tarantool (locally or in Docker) - and make sure that you have created and populated a database as we suggested - :ref:`earlier `: +.. _getting_started_go_sample_db: - .. code-block:: lua +Sample database configuration +----------------------------- - box.cfg{listen = 3301} - s = box.schema.space.create('tester') - s:format({ - {name = 'id', type = 'unsigned'}, - {name = 'band_name', type = 'string'}, - {name = 'year', type = 'unsigned'} - }) - s:create_index('primary', { - type = 'hash', - parts = {'id'} - }) - s:create_index('secondary', { - type = 'hash', - parts = {'band_name'} - }) - s:insert{1, 'Roxette', 1986} - s:insert{2, 'Scorpions', 2015} - s:insert{3, 'Ace of Base', 1993} +.. include:: getting_started_net_box.rst + :start-after: connectors_sample_db_config_start + :end-before: connectors_sample_db_config_end - .. IMPORTANT:: +.. _getting_started_go_sample_db_start: - Please do not close the terminal window - where Tarantool is running -- you'll need it soon. +Starting a sample database application +-------------------------------------- -#. In order to connect to Tarantool as an administrator, reset the password - for the ``admin`` user: +Before creating and starting a client Go application, you need to run the :ref:`sample_db ` application using :ref:`tt start `: - .. code-block:: lua +.. code-block:: console - box.schema.user.passwd('pass') + $ tt start sample_db -.. _getting_started-go-connecting: +Now you can create a client Go application that makes requests to this database. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Connecting to Tarantool -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To get connected to the Tarantool server, write a simple Go program: +.. _getting_started_go_develop_client_app: -.. code-block:: go +Developing a client application +------------------------------- - package main +Before you start, make sure you have `Go installed `__ on your computer. - import ( - "fmt" +.. _getting_started_go_create_client_app: - "github.com/tarantool/go-tarantool" - ) +Creating an application +~~~~~~~~~~~~~~~~~~~~~~~ - func main() { +1. Create the ``hello`` directory for your application and go to this directory: - conn, err := tarantool.Connect("127.0.0.1:3301", tarantool.Opts{ - User: "admin", - Pass: "pass", - }) + .. code-block:: console - if err != nil { - log.Fatalf("Connection refused") - } + $ mkdir hello + $ cd hello - defer conn.Close() +2. Initialize a new Go module: - // Your logic for interacting with the database - } + .. code-block:: console -The default user is ``guest``. + $ go mod init example/hello -.. _getting_started-go-manipulate: +3. Inside the ``hello`` directory, create the ``hello.go`` file for application code. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Manipulating the data -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. _getting_started-go-insert: +.. _getting_started_go_import_: -******************************************************************************** -Inserting data -******************************************************************************** +Importing 'go-tarantool' packages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To insert a :term:`tuple` into a :term:`space`, use ``Insert``: +In the ``hello.go`` file, declare a ``main`` package and import the following packages: -.. code-block:: go +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: package main + :end-before: func main() + :dedent: - resp, err = conn.Insert("tester", []interface{}{4, "ABBA", 1972}) +The packages for external MsgPack types, such as ``datetime``, ``decimal``, or ``uuid``, are required to parse these types in a response. -This inserts the tuple ``(4, "ABBA", 1972)`` into a space named ``tester``. -The response code and data are available in the -`tarantool.Response `_ -structure: +.. _getting_started_go_creating_connection: -.. code-block:: go +Connecting to the database +~~~~~~~~~~~~~~~~~~~~~~~~~~ - code := resp.Code - data := resp.Data +1. Declare the ``main()`` function: -.. _getting_started-go-query: + .. code-block:: go -******************************************************************************** -Querying data -******************************************************************************** + func main() { -To select a tuple from a space, use -`Select `_: + } -.. code-block:: go +2. Inside the ``main()`` function, add the following code: - resp, err = conn.Select("tester", "primary", 0, 1, tarantool.IterEq, []interface{}{4}) + .. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Connect to the database + :end-before: // Insert data + :dedent: -This selects a tuple by the primary key with ``offset = 0`` and ``limit = 1`` -from a space named ``tester`` (in our example, this is the index named ``primary``, -based on the ``id`` field of each tuple). + This code establishes a connection to a running Tarantool instance on behalf of ``sampleuser``. + The ``conn`` object can be used to make CRUD requests and execute stored procedures. -Next, select tuples by a secondary key. -.. code-block:: go - resp, err = conn.Select("tester", "secondary", 0, 1, tarantool.IterEq, []interface{}{"ABBA"}) +.. _getting_started_go_manipulating_data: -Finally, it would be nice to select all the tuples in a space. But there is no -one-liner for this in Go; you would need a script like -:ref:`this one `. +Manipulating data +~~~~~~~~~~~~~~~~~ -For more examples, see https://github.com/tarantool/go-tarantool#usage +.. _getting_started_go_inserting_data: -.. _getting_started-go-update: +Inserting data +************** -******************************************************************************** -Updating data -******************************************************************************** +Add the following code to insert four tuples into the ``bands`` space: -Update a :term:`field` value using ``Update``: +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Insert data + :end-before: // Select by primary key + :dedent: -.. code-block:: go +This code makes insert requests asynchronously: - resp, err = conn.Update("tester", "primary", []interface{}{4}, []interface{}{[]interface{}{"+", 2, 3}}) +- The ``Future`` structure is used as a handle for asynchronous requests. +- The ``NewInsertRequest()`` method creates an insert request object that is executed by the connection. -This increases by 3 the value of field ``2`` in the tuple with ``id = 4``. -If a tuple with this ``id`` doesn't exist, Tarantool will return an error. +.. NOTE:: -Now use ``Replace`` to totally replace the tuple that matches the -primary key. If a tuple with this primary key doesn't exist, Tarantool will -do nothing. + Making requests asynchronously is the recommended way to perform data operations. + Further requests in this tutorial are made synchronously. -.. code-block:: go - resp, err = conn.Replace("tester", []interface{}{4, "New band", 2011}) +.. _getting_started_go_querying_data: -You can also update the data using ``Upsert`` that works similarly -to ``Update``, but creates a new tuple if the old one was not found. +Querying data +************* -.. code-block:: go +To get a tuple by the specified primary key value, use ``NewSelectRequest()`` to create an insert request object: - resp, err = conn.Upsert("tester", []interface{}{4, "Another band", 2000}, []interface{}{[]interface{}{"+", 2, 5}}) +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Select by primary key + :end-at: Tuple selected by the primary key value + :dedent: -This increases by 5 the value of the third field in the tuple with ``id = 4``, or -inserts the tuple ``(4, "Another band", 2000)`` if a tuple with this ``id`` -doesn't exist. +You can also get a tuple by the value of the specified index by using ``Index()``: -.. _getting_started-go-delete: +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Select by secondary key + :end-at: Tuple selected by the secondary key value + :dedent: -******************************************************************************** -Deleting data -******************************************************************************** -To delete a tuple, use ``connection.Delete``: -.. code-block:: go +.. _getting_started_go_updating_data: - resp, err = conn.Delete("tester", "primary", []interface{}{4}) +Updating data +************* -To delete all tuples in a space (or to delete an entire space), use ``Call``. -We'll focus on this function in more detail in the -:ref:`next ` section. +``NewUpdateRequest()`` can be used to update a tuple identified by the primary key as follows: -To delete all tuples in a space, call ``space:truncate``: +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Update + :end-at: Updated tuple + :dedent: -.. code-block:: go +``NewUpsertRequest()`` can be used to update an existing tuple or insert a new one. +In the example below, a new tuple is inserted: - resp, err = conn.Call("box.space.tester:truncate", []interface{}{}) +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Upsert + :end-before: // Replace + :dedent: -To delete an entire space, call ``space:drop``. -This requires connecting to Tarantool as the ``admin`` user: -.. code-block:: go +In this example, ``NewReplaceRequest()`` is used to delete the existing tuple and insert a new one: - resp, err = conn.Call("box.space.tester:drop", []interface{}{}) +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Replace + :end-at: Replaced tuple + :dedent: + + + + +.. _getting_started_go_deleting_data: + +Deleting data +************* -.. _getting_started-go-stored-procs: +``NewDeleteRequest()`` in the example below is used to delete a tuple whose primary key value is ``5``: + +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Delete + :end-at: Deleted tuple + :dedent: + + + +.. _getting_started_go_stored_procedures: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Executing stored procedures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To execute a stored procedure, use ``NewCallRequest()``: + +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Call + :end-at: Stored procedure result + :dedent: + + +.. _getting_started_go_closing_connection: + +Closing the connection +~~~~~~~~~~~~~~~~~~~~~~ + +The ``CloseGraceful()`` method can be used to close the connection when it is no longer needed: + +.. literalinclude:: /code_snippets/snippets/connectors/go/hello.go + :language: go + :start-at: // Close connection + :end-at: Connection is closed + :dedent: + +.. NOTE:: -Switch to the terminal window where Tarantool is running. + You can find the example with all the requests above on GitHub: `go `_. -.. NOTE:: - If you don't have a terminal window with remote connection to Tarantool, - check out these guides: - * :ref:`connecting to a local Tarantool instance ` - * :ref:`attaching to a Tarantool instance that runs in a Docker container ` +.. _getting_started_go_run_client_app: -Define a simple Lua function: +Starting a client application +----------------------------- -.. code-block:: lua +1. Execute the following ``go get`` commands to update dependencies in the ``go.mod`` file: - function sum(a, b) - return a + b - end + .. code-block:: console -Now we have a Lua function defined in Tarantool. To invoke this function from -``go``, use ``Call``: + $ go get github.com/tarantool/go-tarantool/v2 + $ go get github.com/tarantool/go-tarantool/v2/decimal + $ go get github.com/tarantool/go-tarantool/v2/uuid -.. code-block:: go +2. To run the resulting application, execute the ``go run`` command in the application directory: - resp, err = conn.Call("sum", []interface{}{2, 3}) + .. code-block:: console -To send bare Lua code for execution, use ``Eval``: + $ go run . + Inserted tuples: + [[1 Roxette 1986]] + [[2 Scorpions 1965]] + [[3 Ace of Base 1987]] + [[4 The Beatles 1960]] + Tuple selected by the primary key value: [[1 Roxette 1986]] + Tuple selected by the secondary key value: [[4 The Beatles 1960]] + Updated tuple: [[2 Pink Floyd 1965]] + Replaced tuple: [[1 Queen 1970]] + Deleted tuple: [[5 The Rolling Stones 1962]] + Stored procedure result: [[[2 Pink Floyd 1965] [4 The Beatles 1960]]] + Connection is closed -.. code-block:: go - resp, err = connection.Eval("return 4 + 5", []interface{}{}) .. _getting_started-go-comparison: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Feature comparison -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Go connectors feature comparison +-------------------------------- There are two more connectors from the open-source community: diff --git a/doc/how-to/getting_started_net_box.rst b/doc/how-to/getting_started_net_box.rst index 2bb229cec1..44f4e73db2 100644 --- a/doc/how-to/getting_started_net_box.rst +++ b/doc/how-to/getting_started_net_box.rst @@ -14,15 +14,17 @@ For more information about the ``net.box`` module API, check :ref:`net_box-modul Sample database configuration ----------------------------- +.. connectors_sample_db_config_start + This section describes the :ref:`configuration ` of a sample database that allows remote connections: .. literalinclude:: /code_snippets/snippets/connectors/instances.enabled/sample_db/config.yaml :language: yaml :dedent: -- The configuration contains one instance that listens incoming requests on the ``127.0.0.1:3301`` address. +- The configuration contains one instance that listens for incoming requests on the ``127.0.0.1:3301`` address. - ``sampleuser`` has :ref:`privileges ` to select and modify data in the ``bands`` space and execute the ``get_bands_older_than`` stored function. This user can be used to connect to the instance remotely. -- ``myapp.lua`` defines how data is stored in a database and includes a stored function. +- ``myapp.lua`` defines the data model and a stored function. The ``myapp.lua`` file looks as follows: @@ -32,6 +34,8 @@ The ``myapp.lua`` file looks as follows: You can find the full example on GitHub: `sample_db `_. +.. connectors_sample_db_config_end +