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

CreateTag and CreateEdge support TTL #328

Merged
merged 1 commit into from
Apr 2, 2024
Merged
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
82 changes: 61 additions & 21 deletions label.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@
package nebula_go

import (
"fmt"
"strings"
)

type LabelName struct {
Name string `nebula:"Name"`
}

type SpaceName struct {
Name string `nebula:"Name"`
}

type Label struct {
Field string `nebula:"Field"`
Type string `nebula:"Type"`
Expand All @@ -19,21 +28,23 @@ type Label struct {
Comment string `nebula:"Comment"`
}

type LabelSchema struct {
Name string
Fields []LabelFieldSchema
TTLDuration uint
TTLCol string
}

type LabelFieldSchema struct {
Field string
Type string
Nullable bool
haoxins marked this conversation as resolved.
Show resolved Hide resolved
}

type LabelSchema struct {
Name string
Fields []LabelFieldSchema
}

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

fs := []string{}
fields := []string{}
for _, field := range tag.Fields {
t := field.Type
if t == "" {
Expand All @@ -43,10 +54,16 @@ func (tag LabelSchema) BuildCreateTagQL() string {
if !field.Nullable {
n = "NOT NULL"
}
fs = append(fs, field.Field+" "+t+" "+n)
fields = append(fields, field.Field+" "+t+" "+n)
}

q += strings.Join(fs, ", ") + ");"
ttl := tag.buildTTL_QL()

if ttl != "" {
q += strings.Join(fields, ", ") + ") " + ttl + ";"
} else {
q += strings.Join(fields, ", ") + ");"
}

return q
}
Expand All @@ -59,7 +76,7 @@ func (tag LabelSchema) BuildDropTagQL() string {
func (edge LabelSchema) BuildCreateEdgeQL() string {
q := "CREATE EDGE IF NOT EXISTS " + edge.Name + " ("

fs := []string{}
fields := []string{}
for _, field := range edge.Fields {
t := field.Type
if t == "" {
Expand All @@ -69,21 +86,52 @@ func (edge LabelSchema) BuildCreateEdgeQL() string {
if !field.Nullable {
n = "NOT NULL"
}
fs = append(fs, field.Field+" "+t+" "+n)
fields = append(fields, field.Field+" "+t+" "+n)
}

if len(fs) > 0 {
q += strings.Join(fs, ", ")
ttl := edge.buildTTL_QL()

if ttl != "" {
q += strings.Join(fields, ", ") + ") " + ttl + ";"
} else {
q += strings.Join(fields, ", ") + ");"
}

return q + ");"
return q
}

func (edge LabelSchema) BuildDropEdgeQL() string {
q := "DROP EDGE IF EXISTS " + edge.Name + ";"
return q
}

func (label LabelSchema) buildTTL_QL() string {
ttl := ""
if label.TTLCol != "" {
if !label.isTTLColValid() {
panic(fmt.Errorf("TTL column %s does not exist in the fields", label.TTLCol))
}
ttl = fmt.Sprintf(`TTL_DURATION = %d, TTL_COL = "%s"`, label.TTLDuration, label.TTLCol)
}

return ttl
}

func (label LabelSchema) isTTLColValid() bool {
if label.TTLCol == "" {
// no ttl column is valid
return true
}

for _, field := range label.Fields {
if field.Field == label.TTLCol {
return true
}
}

return false
}

func (field LabelFieldSchema) BuildAddTagFieldQL(labelName string) string {
q := "ALTER TAG " + labelName + " ADD (" + field.Field + " " + field.Type
if !field.Nullable {
Expand All @@ -107,11 +155,3 @@ func (field Label) BuildDropTagFieldQL(labelName string) string {
func (field Label) BuildDropEdgeFieldQL(labelName string) string {
return "ALTER EDGE " + labelName + " DROP (" + field.Field + ");"
}

type LabelName struct {
Name string `nebula:"Name"`
}

type SpaceName struct {
Name string `nebula:"Name"`
}
29 changes: 29 additions & 0 deletions label_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ func TestBuildCreateTagQL(t *testing.T) {
}
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())

tag.TTLDuration = 100
tag.TTLCol = "created_at"
assert.PanicsWithError(t, "TTL column created_at does not exist in the fields", func() {
tag.BuildCreateTagQL()
})

tag.Fields = append(tag.Fields, LabelFieldSchema{
Field: "created_at",
Type: "timestamp",
Nullable: true,
})

assert.Equal(t, `CREATE TAG IF NOT EXISTS account (name string NOT NULL, email string NULL, phone string NULL, created_at timestamp NULL) TTL_DURATION = 100, TTL_COL = "created_at";`, tag.BuildCreateTagQL())
}

func TestBuildCreateEdgeQL(t *testing.T) {
Expand All @@ -47,6 +61,21 @@ func TestBuildCreateEdgeQL(t *testing.T) {
}
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())

edge.TTLDuration = 100
edge.TTLCol = "created_at"

assert.PanicsWithError(t, "TTL column created_at does not exist in the fields", func() {
edge.BuildCreateEdgeQL()
})

edge.Fields = append(edge.Fields, LabelFieldSchema{
Field: "created_at",
Type: "timestamp",
Nullable: true,
})

assert.Equal(t, `CREATE EDGE IF NOT EXISTS account_email (email string NOT NULL, created_at timestamp NULL) TTL_DURATION = 100, TTL_COL = "created_at";`, edge.BuildCreateEdgeQL())
}

func TestBuildAddFieldQL(t *testing.T) {
Expand Down
50 changes: 30 additions & 20 deletions schema_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ func (mgr *SchemaManager) WithVerbose(verbose bool) *SchemaManager {
// 2.2 If the field type is different, it will return an error.
// 2.3 If a field exists in the graph but not in the given tag,
// it will be removed.
// 3. If the tag exists and the fields are the same,
// it will be checked if the TTL is set as expected.
//
// Notice:
// We won't change the field type because it has
Expand All @@ -43,7 +45,7 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
// 1. Make sure the tag exists
fields, err := mgr.pool.DescTag(tag.Name)
if err != nil {
// 2. If the tag does not exist, create it
// If the tag does not exist, create it
if strings.Contains(err.Error(), ErrorTagNotFound) {
if mgr.verbose {
log.Printf("ApplyTag: create the not existing tag. name=%s\n", tag.Name)
Expand All @@ -53,15 +55,15 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
return nil, err
}

// 3. The tag exists, add new fields if needed
// 3.1 Prepare the new fields
// 2. The tag exists, add new fields if needed
// 2.1 Prepare the new fields
addFieldQLs := []string{}
for _, expected := range tag.Fields {
found := false
for _, actual := range fields {
if expected.Field == actual.Field {
found = true
// 3.2 Check if the field type is different
// 2.2 Check if the field type is different
if expected.Type != actual.Type {
return nil, fmt.Errorf("field type is different. "+
"Expected: %s, Actual: %s", expected.Type, actual.Type)
Expand All @@ -70,12 +72,12 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
}
}
if !found {
// 3.3 Add the not exists field QL
// 2.3 Add the not exists field QL
q := expected.BuildAddTagFieldQL(tag.Name)
addFieldQLs = append(addFieldQLs, q)
}
}
// 3.4 Execute the add field QLs if needed
// 2.4 Execute the add field QLs if needed
if len(addFieldQLs) > 0 {
queries := strings.Join(addFieldQLs, " ")
if mgr.verbose {
Expand All @@ -87,8 +89,8 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
}
}

// 4. Remove the not expected field if needed
// 4.1 Prepare the not expected fields
// 3. Remove the not expected field if needed
// 3.1 Prepare the not expected fields
dropFieldQLs := []string{}
for _, actual := range fields {
redundant := true
Expand All @@ -99,12 +101,12 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
}
}
if redundant {
// 4.2 Remove the not expected field
// 3.2 Remove the not expected field
q := actual.BuildDropTagFieldQL(tag.Name)
dropFieldQLs = append(dropFieldQLs, q)
}
}
// 4.3 Execute the drop field QLs if needed
// 3.3 Execute the drop field QLs if needed
if len(dropFieldQLs) > 0 {
queries := strings.Join(dropFieldQLs, " ")
if mgr.verbose {
Expand All @@ -116,6 +118,9 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
}
}

// 4. Check if the TTL is set as expected.
// @TODO

return nil, nil
}

Expand All @@ -126,6 +131,8 @@ func (mgr *SchemaManager) ApplyTag(tag LabelSchema) (*ResultSet, error) {
// 2.2 If the field type is different, it will return an error.
// 2.3 If a field exists in the graph but not in the given edge,
// it will be removed.
// 3. If the edge exists and the fields are the same,
// it will be checked if the TTL is set as expected.
//
// Notice:
// We won't change the field type because it has
Expand All @@ -134,7 +141,7 @@ func (mgr *SchemaManager) ApplyEdge(edge LabelSchema) (*ResultSet, error) {
// 1. Make sure the edge exists
fields, err := mgr.pool.DescEdge(edge.Name)
if err != nil {
// 2. If the edge does not exist, create it
// If the edge does not exist, create it
if strings.Contains(err.Error(), ErrorEdgeNotFound) {
if mgr.verbose {
log.Printf("ApplyEdge: create the not existing edge. name=%s\n", edge.Name)
Expand All @@ -144,15 +151,15 @@ func (mgr *SchemaManager) ApplyEdge(edge LabelSchema) (*ResultSet, error) {
return nil, err
}

// 3. The edge exists now, add new fields if needed
// 3.1 Prepare the new fields
// 2. The edge exists now, add new fields if needed
// 2.1 Prepare the new fields
addFieldQLs := []string{}
for _, expected := range edge.Fields {
found := false
for _, actual := range fields {
if expected.Field == actual.Field {
found = true
// 3.2 Check if the field type is different
// 2.2 Check if the field type is different
if expected.Type != actual.Type {
return nil, fmt.Errorf("field type is different. "+
"Expected: %s, Actual: %s", expected.Type, actual.Type)
Expand All @@ -161,12 +168,12 @@ func (mgr *SchemaManager) ApplyEdge(edge LabelSchema) (*ResultSet, error) {
}
}
if !found {
// 3.3 Add the not exists field QL
// 2.3 Add the not exists field QL
q := expected.BuildAddEdgeFieldQL(edge.Name)
addFieldQLs = append(addFieldQLs, q)
}
}
// 3.4 Execute the add field QLs if needed
// 2.4 Execute the add field QLs if needed
if len(addFieldQLs) > 0 {
queries := strings.Join(addFieldQLs, " ")
if mgr.verbose {
Expand All @@ -178,8 +185,8 @@ func (mgr *SchemaManager) ApplyEdge(edge LabelSchema) (*ResultSet, error) {
}
}

// 4. Remove the not expected field if needed
// 4.1 Prepare the not expected fields
// 3. Remove the not expected field if needed
// 3.1 Prepare the not expected fields
dropFieldQLs := []string{}
for _, actual := range fields {
redundant := true
Expand All @@ -190,12 +197,12 @@ func (mgr *SchemaManager) ApplyEdge(edge LabelSchema) (*ResultSet, error) {
}
}
if redundant {
// 4.2 Remove the not expected field
// 3.2 Remove the not expected field
q := actual.BuildDropEdgeFieldQL(edge.Name)
dropFieldQLs = append(dropFieldQLs, q)
}
}
// 4.3 Execute the drop field QLs if needed
// 3.3 Execute the drop field QLs if needed
if len(dropFieldQLs) > 0 {
queries := strings.Join(dropFieldQLs, "")
if mgr.verbose {
Expand All @@ -207,5 +214,8 @@ func (mgr *SchemaManager) ApplyEdge(edge LabelSchema) (*ResultSet, error) {
}
}

// 4. Check if the TTL is set as expected.
// @TODO

return nil, nil
}
Loading
Loading