Skip to content

Commit b82d157

Browse files
author
maksim.konovalov
committed
box: added logic for working with Tarantool schema
Implemented the `box.Schema()` method that returns a `Schema` object for schema-related operations
1 parent d8e2284 commit b82d157

13 files changed

+1436
-50
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
1111
### Added
1212

1313
- Extend box with replication information (#427).
14+
- Implemented all box.schema.user operations requests and sugar interface (#426).
15+
- Implemented box.session.su request and sugar interface only for current session granting (#426).
1416

1517
### Changed
1618

box/box.go

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ func New(conn tarantool.Doer) *Box {
1717
}
1818
}
1919

20+
// Schema returns a new Schema instance, providing access to schema-related operations.
21+
// It uses the connection from the Box instance to communicate with Tarantool.
22+
func (b *Box) Schema() *Schema {
23+
return NewSchema(b.conn)
24+
}
25+
2026
// Info retrieves the current information of the Tarantool instance.
2127
// It calls the "box.info" function and parses the result into the Info structure.
2228
func (b *Box) Info() (Info, error) {

box/example_test.go

+127-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"github.com/tarantool/go-tarantool/v2/box"
1919
)
2020

21-
func Example() {
21+
func ExampleBox_Info() {
2222
dialer := tarantool.NetDialer{
2323
Address: "127.0.0.1:3013",
2424
User: "test",
@@ -58,3 +58,129 @@ func Example() {
5858
fmt.Printf("Box info uuids are equal")
5959
fmt.Printf("Current box info: %+v\n", resp.Info)
6060
}
61+
62+
func ExampleSchemaUser_Exists() {
63+
dialer := tarantool.NetDialer{
64+
Address: "127.0.0.1:3013",
65+
User: "test",
66+
Password: "test",
67+
}
68+
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
69+
client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
70+
cancel()
71+
if err != nil {
72+
log.Fatalf("Failed to connect: %s", err)
73+
}
74+
75+
// You can use UserExistsRequest type and call it directly.
76+
fut := client.Do(box.NewUserExistsRequest("user"))
77+
78+
resp := &box.UserExistsResponse{}
79+
80+
err = fut.GetTyped(resp)
81+
if err != nil {
82+
log.Fatalf("Failed get box schema user exists with error: %s", err)
83+
}
84+
85+
// Or use simple User implementation.
86+
b := box.New(client)
87+
exists, err := b.Schema().User().Exists(ctx, "user")
88+
if err != nil {
89+
log.Fatalf("Failed get box schema user exists with error: %s", err)
90+
}
91+
92+
if exists != resp.Exists {
93+
log.Fatalf("Box schema users exists are not equal")
94+
}
95+
96+
fmt.Printf("Box schema users exists are equal")
97+
fmt.Printf("Current exists state: %+v\n", exists)
98+
}
99+
100+
func ExampleSchemaUser_Create() {
101+
// Connect to Tarantool.
102+
dialer := tarantool.NetDialer{
103+
Address: "127.0.0.1:3013",
104+
User: "test",
105+
Password: "test",
106+
}
107+
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
108+
client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
109+
cancel()
110+
if err != nil {
111+
log.Fatalf("Failed to connect: %s", err)
112+
}
113+
114+
// Create SchemaUser.
115+
schemaUser := box.NewSchemaUser(client)
116+
117+
// Create a new user.
118+
username := "new_user"
119+
options := box.UserCreateOptions{
120+
IfNotExists: true,
121+
Password: "secure_password",
122+
}
123+
err = schemaUser.Create(ctx, username, options)
124+
if err != nil {
125+
log.Fatalf("Failed to create user: %s", err)
126+
}
127+
128+
fmt.Printf("User '%s' created successfully\n", username)
129+
}
130+
131+
func ExampleSchemaUser_Drop() {
132+
// Connect to Tarantool.
133+
dialer := tarantool.NetDialer{
134+
Address: "127.0.0.1:3013",
135+
User: "test",
136+
Password: "test",
137+
}
138+
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
139+
client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
140+
cancel()
141+
if err != nil {
142+
log.Fatalf("Failed to connect: %s", err)
143+
}
144+
145+
// Create SchemaUser.
146+
schemaUser := box.NewSchemaUser(client)
147+
148+
// Drop an existing user.
149+
username := "new_user"
150+
options := box.UserDropOptions{
151+
IfExists: true,
152+
}
153+
err = schemaUser.Drop(ctx, username, options)
154+
if err != nil {
155+
log.Fatalf("Failed to drop user: %s", err)
156+
}
157+
158+
fmt.Printf("User '%s' dropped successfully\n", username)
159+
}
160+
161+
func ExampleSchemaUser_Password() {
162+
// Connect to Tarantool.
163+
dialer := tarantool.NetDialer{
164+
Address: "127.0.0.1:3013",
165+
User: "test",
166+
Password: "test",
167+
}
168+
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
169+
client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
170+
cancel()
171+
if err != nil {
172+
log.Fatalf("Failed to connect: %s", err)
173+
}
174+
175+
// Create SchemaUser.
176+
schemaUser := box.NewSchemaUser(client)
177+
178+
// Get the password hash.
179+
password := "my-password"
180+
passwordHash, err := schemaUser.Password(ctx, password)
181+
if err != nil {
182+
log.Fatalf("Failed to get password hash: %s", err)
183+
}
184+
185+
fmt.Printf("Password '%s' hash: %s\n", password, passwordHash)
186+
}

box/info.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,14 @@ func (ir *InfoResponse) DecodeMsgpack(d *msgpack.Decoder) error {
112112
// InfoRequest represents a request to retrieve information about the Tarantool instance.
113113
// It implements the tarantool.Request interface.
114114
type InfoRequest struct {
115-
baseRequest
116-
}
117-
118-
// Body method is used to serialize the request's body.
119-
// It is part of the tarantool.Request interface implementation.
120-
func (i InfoRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder) error {
121-
return i.impl.Body(res, enc)
115+
*tarantool.CallRequest // Underlying Tarantool call request.
122116
}
123117

124118
// NewInfoRequest returns a new empty info request.
125119
func NewInfoRequest() InfoRequest {
126-
req := InfoRequest{}
127-
req.impl = newCall("box.info")
128-
return req
120+
callReq := tarantool.NewCallRequest("box.info")
121+
122+
return InfoRequest{
123+
callReq,
124+
}
129125
}

box/request.go

-38
This file was deleted.

box/schema.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package box
2+
3+
import "github.com/tarantool/go-tarantool/v2"
4+
5+
// Schema represents the schema-related operations in Tarantool.
6+
// It holds a connection to interact with the Tarantool instance.
7+
type Schema struct {
8+
conn tarantool.Doer // Connection interface for interacting with Tarantool.
9+
}
10+
11+
// NewSchema creates a new Schema instance with the provided Tarantool connection.
12+
// It initializes a Schema object that can be used for schema-related operations
13+
// such as managing users, tables, and other schema elements in the Tarantool instance.
14+
func NewSchema(conn tarantool.Doer) *Schema {
15+
return &Schema{conn: conn} // Pass the connection to the Schema.
16+
}
17+
18+
// User returns a new SchemaUser instance, allowing schema-related user operations.
19+
func (s *Schema) User() *SchemaUser {
20+
return NewSchemaUser(s.conn)
21+
}

box/schema_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package box
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
"github.com/tarantool/go-tarantool/v2"
9+
"github.com/tarantool/go-tarantool/v2/test_helpers"
10+
)
11+
12+
func TestNewSchema(t *testing.T) {
13+
ctx := context.Background()
14+
15+
// Create a schema instance with a nil connection. This should lead to a panic later.
16+
b := NewSchema(nil)
17+
18+
// Ensure the schema is not nil (which it shouldn't be), but this is not meaningful
19+
// since we will panic when we call the schema methods with the nil connection.
20+
t.Run("internal sugar sub-objects not panics", func(t *testing.T) {
21+
require.NotNil(t, b)
22+
require.NotNil(t, b.User())
23+
})
24+
25+
t.Run("check that connections are equal", func(t *testing.T) {
26+
var tCases []tarantool.Doer
27+
for i := 0; i < 10; i++ {
28+
29+
doer := test_helpers.NewMockDoer(t)
30+
tCases = append(tCases, &doer)
31+
}
32+
33+
for _, tCase := range tCases {
34+
sch := NewSchema(tCase)
35+
require.Equal(t, tCase, sch.conn)
36+
require.Equal(t, tCase, sch.User().conn)
37+
}
38+
})
39+
40+
t.Run("nil conn panics", func(t *testing.T) {
41+
require.Panics(t, func() {
42+
_, _ = b.User().Info(ctx, "panic-on")
43+
})
44+
})
45+
}

0 commit comments

Comments
 (0)