Skip to content

Added logic for working with Tarantool schema via Box #426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.

### Added

- Implemented all box.schema.user operations requests and sugar interface (#426).
- Implemented box.session.su request and sugar interface only for current session granting (#426).

### Changed

### Fixed
Expand Down
6 changes: 6 additions & 0 deletions box/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ func New(conn tarantool.Doer) *Box {
}
}

// Schema returns a new Schema instance, providing access to schema-related operations.
// It uses the connection from the Box instance to communicate with Tarantool.
func (b *Box) Schema() *Schema {
return NewSchema(b.conn)
}

// Info retrieves the current information of the Tarantool instance.
// It calls the "box.info" function and parses the result into the Info structure.
func (b *Box) Info() (Info, error) {
Expand Down
189 changes: 186 additions & 3 deletions box/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
// Terminal 2:
// $ go test -v example_test.go

package box_test

import (
Expand All @@ -18,7 +19,7 @@ import (
"github.com/tarantool/go-tarantool/v2/box"
)

func Example() {
func ExampleBox_Info() {
dialer := tarantool.NetDialer{
Address: "127.0.0.1:3013",
User: "test",
Expand Down Expand Up @@ -55,6 +56,188 @@ func Example() {
log.Fatalf("Box info uuids are not equal")
}

fmt.Printf("Box info uuids are equal")
fmt.Printf("Current box info: %+v\n", resp.Info)
fmt.Printf("Box info uuids are equal\n")
fmt.Printf("Current box ro: %+v", resp.Info.RO)
// Output:
// Box info uuids are equal
// Current box ro: false
}

func ExampleSchemaUser_Exists() {
dialer := tarantool.NetDialer{
Address: "127.0.0.1:3013",
User: "test",
Password: "test",
}
ctx := context.Background()

client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})

if err != nil {
log.Fatalf("Failed to connect: %s", err)
}

// You can use UserExistsRequest type and call it directly.
fut := client.Do(box.NewUserExistsRequest("user"))

resp := &box.UserExistsResponse{}

err = fut.GetTyped(resp)
if err != nil {
log.Fatalf("Failed get box schema user exists with error: %s", err)
}

// Or use simple User implementation.
b := box.New(client)
exists, err := b.Schema().User().Exists(ctx, "user")
if err != nil {
log.Fatalf("Failed get box schema user exists with error: %s", err)
}

if exists != resp.Exists {
log.Fatalf("Box schema users exists are not equal")
}

fmt.Printf("Box schema users exists are equal\n")
fmt.Printf("Current exists state: %+v", exists)
// Output:
// Box schema users exists are equal
// Current exists state: false
}

func ExampleSchemaUser_Create() {
// Connect to Tarantool.
dialer := tarantool.NetDialer{
Address: "127.0.0.1:3013",
User: "test",
Password: "test",
}
ctx := context.Background()

client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
if err != nil {
log.Fatalf("Failed to connect: %s", err)
}

// Create SchemaUser.
schemaUser := box.NewSchemaUser(client)

// Create a new user.
username := "new_user"
options := box.UserCreateOptions{
IfNotExists: true,
Password: "secure_password",
}
err = schemaUser.Create(ctx, username, options)
if err != nil {
log.Fatalf("Failed to create user: %s", err)
}

fmt.Printf("User '%s' created successfully\n", username)
// Output:
// User 'new_user' created successfully
}

func ExampleSchemaUser_Drop() {
// Connect to Tarantool.
dialer := tarantool.NetDialer{
Address: "127.0.0.1:3013",
User: "test",
Password: "test",
}
ctx := context.Background()

client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
if err != nil {
log.Fatalf("Failed to connect: %s", err)
}

// Create SchemaUser.
schemaUser := box.NewSchemaUser(client)

// Drop an existing user.
username := "new_user"
options := box.UserDropOptions{
IfExists: true,
}
err = schemaUser.Drop(ctx, username, options)
if err != nil {
log.Fatalf("Failed to drop user: %s", err)
}

exists, err := schemaUser.Exists(ctx, username)
if err != nil {
log.Fatalf("Failed to get user exists: %s", err)
}

fmt.Printf("User '%s' dropped successfully\n", username)
fmt.Printf("User '%s' exists status: %v \n", username, exists)
// Output:
// User 'new_user' dropped successfully
// User 'new_user' exists status: false
}

func ExampleSchemaUser_Password() {
// Connect to Tarantool.
dialer := tarantool.NetDialer{
Address: "127.0.0.1:3013",
User: "test",
Password: "test",
}
ctx := context.Background()

client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
if err != nil {
log.Fatalf("Failed to connect: %s", err)
}

// Create SchemaUser.
schemaUser := box.NewSchemaUser(client)

// Get the password hash.
password := "my-password"
passwordHash, err := schemaUser.Password(ctx, password)
if err != nil {
log.Fatalf("Failed to get password hash: %s", err)
}

fmt.Printf("Password '%s' hash: %s", password, passwordHash)
// Output:
// Password 'my-password' hash: 3PHNAQGFWFo0KRfToxNgDXHj2i8=
}

func ExampleSchemaUser_Info() {
// Connect to Tarantool.
dialer := tarantool.NetDialer{
Address: "127.0.0.1:3013",
User: "test",
Password: "test",
}
ctx := context.Background()

client, err := tarantool.Connect(ctx, dialer, tarantool.Opts{})
if err != nil {
log.Fatalf("Failed to connect: %s", err)
}

// Create SchemaUser.
schemaUser := box.NewSchemaUser(client)

info, err := schemaUser.Info(ctx, "test")
if err != nil {
log.Fatalf("Failed to get password hash: %s", err)
}

hasSuper := false
for _, i := range info {
if i.Name == "super" && i.Type == box.PrivilegeRole {
hasSuper = true
}
}

if hasSuper {
fmt.Printf("User have super privileges")
}
// Output:
// User have super privileges
}
16 changes: 6 additions & 10 deletions box/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,14 @@ func (ir *InfoResponse) DecodeMsgpack(d *msgpack.Decoder) error {
// InfoRequest represents a request to retrieve information about the Tarantool instance.
// It implements the tarantool.Request interface.
type InfoRequest struct {
baseRequest
}

// Body method is used to serialize the request's body.
// It is part of the tarantool.Request interface implementation.
func (i InfoRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder) error {
return i.impl.Body(res, enc)
*tarantool.CallRequest // Underlying Tarantool call request.
}

// NewInfoRequest returns a new empty info request.
func NewInfoRequest() InfoRequest {
req := InfoRequest{}
req.impl = newCall("box.info")
return req
callReq := tarantool.NewCallRequest("box.info")

return InfoRequest{
callReq,
}
}
38 changes: 0 additions & 38 deletions box/request.go

This file was deleted.

21 changes: 21 additions & 0 deletions box/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package box

import "github.com/tarantool/go-tarantool/v2"

// Schema represents the schema-related operations in Tarantool.
// It holds a connection to interact with the Tarantool instance.
type Schema struct {
conn tarantool.Doer // Connection interface for interacting with Tarantool.
}

// NewSchema creates a new Schema instance with the provided Tarantool connection.
// It initializes a Schema object that can be used for schema-related operations
// such as managing users, tables, and other schema elements in the Tarantool instance.
func NewSchema(conn tarantool.Doer) *Schema {
return &Schema{conn: conn} // Pass the connection to the Schema.
}

// User returns a new SchemaUser instance, allowing schema-related user operations.
func (s *Schema) User() *SchemaUser {
return NewSchemaUser(s.conn)
}
39 changes: 39 additions & 0 deletions box/schema_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package box

import (
"context"
"testing"

"github.com/stretchr/testify/require"
"github.com/tarantool/go-tarantool/v2"
"github.com/tarantool/go-tarantool/v2/test_helpers"
)

func TestSchemaNotNil(t *testing.T) {
b := NewSchema(nil)
require.NotNil(t, b)
require.NotNil(t, b.User())
}

func TestSchemaConnectionsEquality(t *testing.T) {
var tCases []tarantool.Doer
for i := 0; i < 10; i++ {
doer := test_helpers.NewMockDoer(t)
tCases = append(tCases, &doer)
}

for _, tCase := range tCases {
sch := NewSchema(tCase)
require.Equal(t, tCase, sch.conn)
require.Equal(t, tCase, sch.User().conn)
}
}

func TestSchemaNilConnectionPanics(t *testing.T) {
ctx := context.Background()
b := NewSchema(nil)

require.Panics(t, func() {
_, _ = b.User().Info(ctx, "panic-on")
})
}
Loading
Loading