Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
203 lines (173 sloc) 4.75 KB
// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
// Package dsl provide an API for writing gremlin dsl queries almost as-is
// in Go without using strings in the code.
//
// Note that, the API is not type-safe and assume the provided query and
// its arguments are valid.
package dsl
import (
"fmt"
"strings"
"time"
)
// Node represents a DSL step in the traversal.
type Node interface {
// Code returns the code representation of the element and its bindings (if any).
Code() (string, []interface{})
}
type (
// Token holds a simple token, like assignment.
Token string
// List represents a list of elements.
List struct {
Elements []interface{}
}
// Func represents a function call.
Func struct {
Name string
Args []interface{}
}
// Block represents a block/group of nodes.
Block struct {
Nodes []interface{}
}
// Var represents a variable assignment and usage.
Var struct {
Name string
Elem interface{}
}
)
// Code stringified the token.
func (t Token) Code() (string, []interface{}) { return string(t), nil }
// Code returns the code representation of a list.
func (l List) Code() (string, []interface{}) {
c, args := codeList(", ", l.Elements...)
return fmt.Sprintf("[%s]", c), args
}
// Code returns the code representation of a function call.
func (f Func) Code() (string, []interface{}) {
c, args := codeList(", ", f.Args...)
return fmt.Sprintf("%s(%s)", f.Name, c), args
}
// Code returns the code representation of group/block of nodes.
func (b Block) Code() (string, []interface{}) {
return codeList("; ", b.Nodes...)
}
// Code returns the code representation of variable declaration or its identifier.
func (v Var) Code() (string, []interface{}) {
c, args := code(v.Elem)
if v.Name == "" {
return c, args
}
return fmt.Sprintf("%s = %s", v.Name, c), args
}
// predefined nodes.
var (
G = Token("g")
Dot = Token(".")
)
// NewFunc returns a new function node.
func NewFunc(name string, args ...interface{}) *Func {
return &Func{Name: name, Args: args}
}
// NewList returns a new list node.
func NewList(args ...interface{}) *List {
return &List{Elements: args}
}
// Querier is the interface that wraps the Query method.
type Querier interface {
// Query returns the query-string (similar to the Gremlin byte-code) and its bindings.
Query() (string, Bindings)
}
// Bindings are used to associate a variable with a value.
type Bindings map[string]interface{}
// Add adds new value to the bindings map, formats it if needed, and returns its generated name.
func (b Bindings) Add(v interface{}) string {
k := fmt.Sprintf("$%x", len(b))
switch v := v.(type) {
case time.Time:
b[k] = v.UnixNano()
default:
b[k] = v
}
return k
}
// Cardinality of vertex properties.
type Cardinality string
// Cardinality options.
const (
Set Cardinality = "set"
Single Cardinality = "single"
)
// Code implements the Node interface.
func (c Cardinality) Code() (string, []interface{}) { return string(c), nil }
// Order of vertex properties.
type Order string
// Order options.
const (
Incr Order = "incr"
Decr Order = "decr"
Shuffle Order = "shuffle"
)
// Code implements the Node interface.
func (o Order) Code() (string, []interface{}) { return string(o), nil }
// Column references a particular type of column in a complex data structure such as a Map, a Map.Entry, or a Path.
type Column string
// Column options.
const (
Keys Column = "keys"
Values Column = "values"
)
// Code implements the Node interface.
func (o Column) Code() (string, []interface{}) { return string(o), nil }
// Scope used for steps that have a variable scope which alter the manner in which the step will behave in relation to how the traverses are processed.
type Scope string
// Scope options.
const (
Local Scope = "local"
Global Scope = "global"
)
// Code implements the Node interface.
func (s Scope) Code() (string, []interface{}) { return string(s), nil }
func codeList(sep string, vs ...interface{}) (string, []interface{}) {
var (
br strings.Builder
args []interface{}
)
for i, node := range vs {
if i > 0 {
br.WriteString(sep)
}
c, nargs := code(node)
br.WriteString(c)
args = append(args, nargs...)
}
return br.String(), args
}
func code(v interface{}) (string, []interface{}) {
switch n := v.(type) {
case Node:
return n.Code()
case *Traversal:
var (
b strings.Builder
args []interface{}
)
for i := range n.nodes {
code, nargs := n.nodes[i].Code()
b.WriteString(code)
args = append(args, nargs...)
}
return b.String(), args
default:
return "%s", []interface{}{v}
}
}
func sface(args []string) (v []interface{}) {
for _, s := range args {
v = append(v, s)
}
return
}
You can’t perform that action at this time.