Skip to content

Commit

Permalink
AddTag and AddEdge support TTL (#328)
Browse files Browse the repository at this point in the history
Supports build QL with TTL

wip

fix

docs

fix
  • Loading branch information
haoxins authored Apr 2, 2024
1 parent 7953667 commit 150403c
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 41 deletions.
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
}

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

0 comments on commit 150403c

Please sign in to comment.