Skip to content

Commit 75e1930

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

11 files changed

+692
-50
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ 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 box.schema.user operations requests and sugar interface.
1415

1516
### Changed
1617

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 of an existing user
179+
username := "existing_user"
180+
passwordHash, err := schemaUser.Password(ctx, username)
181+
if err != nil {
182+
log.Fatalf("Failed to get password hash: %s", err)
183+
}
184+
185+
fmt.Printf("Password hash for user '%s': %s\n", username, 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

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package box
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestNewSchema(t *testing.T) {
10+
// Create a schema instance with a nil connection. This should lead to a panic later.
11+
b := NewSchema(nil)
12+
13+
// Ensure the schema is not nil (which it shouldn't be), but this is not meaningful
14+
// since we will panic when we call the schema methods with the nil connection.
15+
require.NotNil(t, b)
16+
}

0 commit comments

Comments
 (0)