Skip to content

Commit 40555ec

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 40555ec

13 files changed

+1459
-52
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

+150-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
// Terminal 2:
88
// $ go test -v example_test.go
9+
910
package box_test
1011

1112
import (
@@ -18,7 +19,7 @@ import (
1819
"github.com/tarantool/go-tarantool/v2/box"
1920
)
2021

21-
func Example() {
22+
func ExampleBox_Info() {
2223
dialer := tarantool.NetDialer{
2324
Address: "127.0.0.1:3013",
2425
User: "test",
@@ -55,6 +56,152 @@ func Example() {
5556
log.Fatalf("Box info uuids are not equal")
5657
}
5758

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

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)