Skip to content
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

Add some schema helper methods for SessionPool #312

Merged
merged 11 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
78 changes: 78 additions & 0 deletions label.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package nebula_go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add copyright for new files.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


import (
"strings"
)

type Label struct {
Field string `nebula:"Field"`
Type string `nebula:"Type"`
Null string `nebula:"Null"`
Default string `nebula:"Default"`
Comment string `nebula:"Comment"`
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can define LabelName here to represent the result of show tags/show edges.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

type LabelFieldSchema struct {
Field string
Type string
Null bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsNull is better for bool var name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I change it to Nullable

}

type LabelSchema struct {
Name string
Fields []LabelFieldSchema
}

func (tag LabelSchema) BuildCreateTagQL() string {
q := "CREATE TAG IF NOT EXISTS " + tag.Name + " ("

fs := []string{}
for _, field := range tag.Fields {
t := field.Type
if t == "" {
t = "string"
}
n := "NULL"
if !field.Null {
n = "NOT NULL"
}
fs = append(fs, field.Field+" "+t+" "+n)
}

q += strings.Join(fs, ", ") + ");"

return q
}

func (tag LabelSchema) BuildDropTagQL() string {
q := "DROP TAG IF EXISTS " + tag.Name + ";"
return q
}

func (edge LabelSchema) BuildCreateEdgeQL() string {
q := "CREATE EDGE IF NOT EXISTS " + edge.Name + " ("

fs := []string{}
for _, field := range edge.Fields {
t := field.Type
if t == "" {
t = "string"
}
n := "NULL"
if !field.Null {
n = "NOT NULL"
}
fs = append(fs, field.Field+" "+t+" "+n)
}

if len(fs) > 0 {
q += strings.Join(fs, ", ")
}

return q + ");"
}

func (edge LabelSchema) BuildDropEdgeQL() string {
q := "DROP EDGE IF EXISTS " + edge.Name + ";"
return q
}
43 changes: 43 additions & 0 deletions label_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package nebula_go

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestBuildCreateTagQL(t *testing.T) {
tag := LabelSchema{
Name: "account",
Fields: []LabelFieldSchema{
{
Field: "name",
Null: false,
},
{
Field: "email",
Null: true,
},
{
Field: "phone",
Null: true,
},
},
}
assert.Equal(t, "CREATE TAG IF NOT EXISTS account (name string NOT NULL, email string NULL, phone string NULL);", tag.BuildCreateTagQL())
assert.Equal(t, "DROP TAG IF EXISTS account;", tag.BuildDropTagQL())
}

func TestBuildCreateEdgeQL(t *testing.T) {
edge := LabelSchema{
Name: "account_email",
Fields: []LabelFieldSchema{
{
Field: "email",
Null: false,
},
},
}
assert.Equal(t, "CREATE EDGE IF NOT EXISTS account_email (email string NOT NULL);", edge.BuildCreateEdgeQL())
assert.Equal(t, "DROP EDGE IF EXISTS account_email;", edge.BuildDropEdgeQL())
}
97 changes: 97 additions & 0 deletions session_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,103 @@ func (pool *SessionPool) GetTotalSessionCount() int {
return pool.activeSessions.Len() + pool.idleSessions.Len()
}

func (pool *SessionPool) ExecuteAndCheck(q string) (*ResultSet, error) {
rs, err := pool.Execute(q)
if err != nil {
return nil, err
}

errCode := rs.GetErrorCode()
if errCode != ErrorCode_SUCCEEDED {
errMsg := rs.GetErrorMsg()
return nil, fmt.Errorf("Fail to execute query. %s", errMsg)
}

return rs, nil
}

type _Label struct {
haoxins marked this conversation as resolved.
Show resolved Hide resolved
Name string `nebula:"Name"`
}

func (pool *SessionPool) ShowTags() ([]string, error) {
rs, err := pool.ExecuteAndCheck("SHOW TAGS;")
if err != nil {
return nil, err
}

var tags []_Label
rs.Scan(&tags)

var names []string
for _, tag := range tags {
names = append(names, tag.Name)
}

return names, nil
}

func (pool *SessionPool) CreateTag(tag LabelSchema) (*ResultSet, error) {
q := tag.BuildCreateTagQL()
rs, err := pool.ExecuteAndCheck(q)
if err != nil {
return rs, err
}
return rs, nil
}

func (pool *SessionPool) DescTag(tagName string) ([]Label, error) {
q := fmt.Sprintf("DESC TAG %s;", tagName)
rs, err := pool.ExecuteAndCheck(q)
if err != nil {
return nil, err
}

var fields []Label
rs.Scan(&fields)

return fields, nil
}

func (pool *SessionPool) ShowEdges() ([]string, error) {
rs, err := pool.ExecuteAndCheck("SHOW EDGES;")
if err != nil {
return nil, err
}

var edges []_Label
rs.Scan(&edges)

var names []string
for _, edge := range edges {
names = append(names, edge.Name)
}

return names, nil
}

func (pool *SessionPool) CreateEdge(edge LabelSchema) (*ResultSet, error) {
q := edge.BuildCreateEdgeQL()
rs, err := pool.ExecuteAndCheck(q)
if err != nil {
return rs, err
}
return rs, nil
}

func (pool *SessionPool) DescEdge(edgeName string) ([]Label, error) {
q := fmt.Sprintf("DESC EDGE %s;", edgeName)
rs, err := pool.ExecuteAndCheck(q)
if err != nil {
return nil, err
}

var fields []Label
rs.Scan(&fields)

return fields, nil
}

// newSession creates a new session and returns it.
// `use <space>` will be executed so that the new session will be in the default space.
func (pool *SessionPool) newSession() (*pureSession, error) {
Expand Down
95 changes: 95 additions & 0 deletions session_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,101 @@ func TestSessionPoolSpaceChange(t *testing.T) {
assert.Equal(t, resultSet.GetSpaceName(), "test_space_1", "space name should be test_space_1")
}

func TestSessionPoolApplySchema(t *testing.T) {
err := prepareSpace("test_space_schema")
if err != nil {
t.Fatal(err)
}
defer dropSpace("test_space_schema")

hostAddress := HostAddress{Host: address, Port: port}
config, err := NewSessionPoolConf(
"root",
"nebula",
[]HostAddress{hostAddress},
"test_space_schema")
if err != nil {
t.Errorf("failed to create session pool config, %s", err.Error())
}

// allow only one session in the pool so it is easier to test
config.maxSize = 1

// create session pool
sessionPool, err := NewSessionPool(*config, DefaultLogger{})
if err != nil {
t.Fatal(err)
}
defer sessionPool.Close()

tagSchema := LabelSchema{
Name: "account",
Fields: []LabelFieldSchema{
{
Field: "name",
Null: false,
},
{
Field: "email",
Null: true,
},
{
Field: "phone",
Type: "int64",
Null: true,
},
},
}
_, err = sessionPool.CreateTag(tagSchema)
if err != nil {
t.Fatal(err)
}
tags, err := sessionPool.ShowTags()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 1, len(tags), "should have 1 tags")
assert.Equal(t, "account", tags[0], "tag name should be account")
labels, err := sessionPool.DescTag("account")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 3, len(labels), "should have 3 labels")
assert.Equal(t, "name", labels[0].Field, "field name should be name")
assert.Equal(t, "string", labels[0].Type, "field type should be string")
assert.Equal(t, "email", labels[1].Field, "field name should be email")
assert.Equal(t, "string", labels[1].Type, "field type should be string")
assert.Equal(t, "phone", labels[2].Field, "field name should be phone")
assert.Equal(t, "int64", labels[2].Type, "field type should be string")

edgeSchema := LabelSchema{
Name: "account_email",
Fields: []LabelFieldSchema{
{
Field: "email",
Null: false,
},
},
}
_, err = sessionPool.CreateEdge(edgeSchema)
if err != nil {
t.Fatal(err)
}
edges, err := sessionPool.ShowEdges()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 1, len(edges), "should have 1 edges")
assert.Equal(t, "account_email", edges[0], "edge name should be account_email")
labels, err = sessionPool.DescEdge("account_email")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 1, len(labels), "should have 1 labels")
assert.Equal(t, "email", labels[0].Field, "field name should be email")
assert.Equal(t, "string", labels[0].Type, "field type should be string")
}

func TestIdleSessionCleaner(t *testing.T) {
err := prepareSpace("client_test")
if err != nil {
Expand Down