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

Clear/struct #1226

Closed
wants to merge 7 commits into from
Closed
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
93 changes: 58 additions & 35 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ const (
DEL
)

// A Req represents a single request to the backend Dgraph instance. Each request may contain
// multiple set, delete and schema mutations, and a single GraphQL+- query. If the query contains
// A Req represents a single request to the backend Dgraph instance. Each request may contain
// multiple set, delete and schema mutations, and a single GraphQL+- query. If the query contains
// GraphQL variables, then it must be set with SetQueryWithVariables rather than SetQuery.
type Req struct {
gr protos.Request
Expand Down Expand Up @@ -92,10 +92,10 @@ func (req *Req) addMutation(e Edge, op opType) {
}
}

// Set adds edge e to the set mutation of request req, thus scheduling the edge to be added to the
// graph when the request is run. The edge must have a valid target (a Node or value), otherwise
// an error is returned. The edge is not checked agaist the schema until the request is
// run --- so setting a UID edge to a value, for example, doesn't result in an error until
// Set adds edge e to the set mutation of request req, thus scheduling the edge to be added to the
// graph when the request is run. The edge must have a valid target (a Node or value), otherwise
// an error is returned. The edge is not checked agaist the schema until the request is
// run --- so setting a UID edge to a value, for example, doesn't result in an error until
// the request is run.
func (req *Req) Set(e Edge) error {
if err := e.validate(); err != nil {
Expand All @@ -106,7 +106,7 @@ func (req *Req) Set(e Edge) error {
}

// Delete adds edge e to the delete mutation of request req, thus scheduling the edge to be removed
// from the graph when the request is run. The edge must have a valid target (a Node or value),
// from the graph when the request is run. The edge must have a valid target (a Node or value),
// otherwise an error is returned. The edge need not represent
// an edge in the graph --- applying such a mutation simply has no effect.
func (req *Req) Delete(e Edge) error {
Expand All @@ -126,7 +126,6 @@ func (req *Req) AddSchema(s protos.SchemaUpdate) error {
return nil
}


func (req *Req) size() int {
if req.gr.Mutation == nil {
return 0
Expand Down Expand Up @@ -161,14 +160,18 @@ func (n Node) String() string {
return n.varName
}

// ConnectTo creates an edge labelled pred from Node n to Node n1
func (n *Node) ConnectTo(pred string, n1 Node) Edge {
e := Edge{}
func (e *Edge) setSubject(n *Node) {
if len(n.varName) != 0 {
e.nq.SubjectVar = n.String()
} else {
e.nq.Subject = n.String()
}
}

// ConnectTo creates an edge labelled pred from Node n to Node n1
func (n *Node) ConnectTo(pred string, n1 Node) Edge {
e := Edge{}
(&e).setSubject(n)
e.nq.Predicate = pred
e.ConnectTo(n1)
return e
Expand All @@ -181,15 +184,21 @@ func (n *Node) ConnectTo(pred string, n1 Node) Edge {
// a request will result in an error --- until it is completed.
func (n *Node) Edge(pred string) Edge {
e := Edge{}
if len(n.varName) != 0 {
e.nq.SubjectVar = n.String()
} else {
e.nq.Subject = n.String()
}
(&e).setSubject(n)
e.nq.Predicate = pred
return e
}

// Delete is used to delete all outgoing edges for a node. It is equivalent to performing a S * *
// deletion.
func (n *Node) Delete() Edge {
e := Edge{}
(&e).setSubject(n)
e.nq.Predicate = x.Star
e.nq.ObjectValue, _ = types.ObjectValue(types.DefaultID, x.Star)
return e
}

// An Edge represents an edge between a source node and a target (either a node or a value).
// Facets are stored in the edge. See Node.Edge(), Node.ConnectTo(), Edge.ConnecTo(),
// Edge.AddFacet and the Edge.SetValue...() functions to
Expand Down Expand Up @@ -217,7 +226,21 @@ func (e *Edge) ConnectTo(n Node) error {
return nil
}

// Delete is used to set the edge for deletion. If the edge is already connected to another node
// then an error is returned. This is equivalent to S P * deletion where an edge can be deleted
// without knowing giving the Value/Node it is connected to.
func (e *Edge) Delete() error {
if len(e.nq.ObjectId) > 0 {
return ErrConnected
}
e.nq.ObjectValue, _ = types.ObjectValue(types.DefaultID, x.Star)
return nil
}

func (e *Edge) validate() error {
if len(e.nq.Subject) == 0 && len(e.nq.SubjectVar) == 0 {
return ErrInvalidSubject
}
// Edge should be connected to a value in which case ObjectType would be > 0.
// Or it needs to connect to a Node (ObjectId > 0) or it should be connected to a variable.
if e.nq.ObjectValue != nil || len(e.nq.ObjectId) > 0 || len(e.nq.ObjectVar) > 0 {
Expand All @@ -235,10 +258,10 @@ func validateStr(val string) error {
return nil
}

// SetValueString sets the value of Edge e as string val and sets the type of the edge to
// types.StringID. If the edge had previous been assigned another value (even of another type),
// the value and type are overwritten. If the edge has previously been connected to a node, the
// edge and type are left unchanged and ErrConnected is returned. The string must
// SetValueString sets the value of Edge e as string val and sets the type of the edge to
// types.StringID. If the edge had previous been assigned another value (even of another type),
// the value and type are overwritten. If the edge has previously been connected to a node, the
// edge and type are left unchanged and ErrConnected is returned. The string must
// escape " with \, otherwise the edge and type are left unchanged and an error returned.
func (e *Edge) SetValueString(val string) error {
if len(e.nq.ObjectId) > 0 {
Expand All @@ -259,7 +282,7 @@ func (e *Edge) SetValueString(val string) error {

// SetValueInt sets the value of Edge e as int64 val and sets the type of the edge to types.IntID.
// If the edge had previous been assigned another value (even of another type), the value and type
// are overwritten. If the edge has previously been connected to a node, the edge and type are
// are overwritten. If the edge has previously been connected to a node, the edge and type are
// left unchanged and ErrConnected is returned.
func (e *Edge) SetValueInt(val int64) error {
if len(e.nq.ObjectId) > 0 {
Expand All @@ -274,8 +297,8 @@ func (e *Edge) SetValueInt(val int64) error {
return nil
}

// SetValueFloat sets the value of Edge e as float64 val and sets the type of the edge to
// types.FloatID. If the edge had previous been assigned another value (even of another type),
// SetValueFloat sets the value of Edge e as float64 val and sets the type of the edge to
// types.FloatID. If the edge had previous been assigned another value (even of another type),
// the value and type are overwritten. If the edge has previously been connected to a node, the
// edge and type are left unchanged and ErrConnected is returned.
func (e *Edge) SetValueFloat(val float64) error {
Expand All @@ -293,7 +316,7 @@ func (e *Edge) SetValueFloat(val float64) error {

// SetValueBool sets the value of Edge e as bool val and sets the type of the edge to types.BoolID.
// If the edge had previous been assigned another value (even of another type), the value and type
// are overwritten. If the edge has previously been connected to a node, the edge and type are
// are overwritten. If the edge has previously been connected to a node, the edge and type are
// left unchanged and ErrConnected is returned.
func (e *Edge) SetValueBool(val bool) error {
if len(e.nq.ObjectId) > 0 {
Expand All @@ -308,9 +331,9 @@ func (e *Edge) SetValueBool(val bool) error {
return nil
}

// SetValuePassword sets the value of Edge e as password string val and sets the type of the edge
// to types.PasswordID. If the edge had previous been assigned another value (even of another
// type), the value and type are overwritten. If the edge has previously been connected to a
// SetValuePassword sets the value of Edge e as password string val and sets the type of the edge
// to types.PasswordID. If the edge had previous been assigned another value (even of another
// type), the value and type are overwritten. If the edge has previously been connected to a
// node, the edge and type are left unchanged and ErrConnected is returned.
func (e *Edge) SetValuePassword(val string) error {
if len(e.nq.ObjectId) > 0 {
Expand All @@ -325,8 +348,8 @@ func (e *Edge) SetValuePassword(val string) error {
return nil
}

// SetValueDatetime sets the value of Edge e as time.Time dateTime and sets the type of the edge
// to types.DateTimeID. If the edge had previous been assigned another value (even of another
// SetValueDatetime sets the value of Edge e as time.Time dateTime and sets the type of the edge
// to types.DateTimeID. If the edge had previous been assigned another value (even of another
// type), the value and type are overwritten. If the edge has previously been connected to a node,
// the edge and type are left unchanged and ErrConnected is returned.
func (e *Edge) SetValueDatetime(dateTime time.Time) error {
Expand All @@ -345,7 +368,7 @@ func (e *Edge) SetValueDatetime(dateTime time.Time) error {
// SetValueGeoJson sets the value of Edge e as the GeoJSON object parsed from json string and sets
// the type of the edge to types.GeoID. If the edge had previous been assigned another value (even
// of another type), the value and type are overwritten. If the edge has previously been connected
// to a node, the edge and type are left unchanged and ErrConnected is returned. If the string
// to a node, the edge and type are left unchanged and ErrConnected is returned. If the string
// fails to parse with geojson.Unmarshal() the edge is left unchanged and an error returned.
func (e *Edge) SetValueGeoJson(json string) error {
if len(e.nq.ObjectId) > 0 {
Expand All @@ -368,9 +391,9 @@ func (e *Edge) SetValueGeoJson(json string) error {
return nil
}

// SetValueDefault sets the value of Edge e as string val and sets the type of the edge to
// types.DefaultID. If the edge had previous been assigned another value (even of another
// type), the value and type are overwritten. If the edge has previously been connected to
// SetValueDefault sets the value of Edge e as string val and sets the type of the edge to
// types.DefaultID. If the edge had previous been assigned another value (even of another
// type), the value and type are overwritten. If the edge has previously been connected to
// a node, the edge and type are left unchanged and ErrConnected is returned.
// The string must escape " with \, otherwise the edge and type are left unchanged and an error returned.
func (e *Edge) SetValueDefault(val string) error {
Expand All @@ -390,9 +413,9 @@ func (e *Edge) SetValueDefault(val string) error {
return nil
}

// SetValueBytes allows setting the value of an edge to raw bytes and sets the type of the edge
// SetValueBytes allows setting the value of an edge to raw bytes and sets the type of the edge
// to types.BinaryID. If the edge had previous been assigned another value (even of another type),
// the value and type are overwritten. If the edge has previously been connected to a node, the
// the value and type are overwritten. If the edge has previously been connected to a node, the
// edge and type are left unchanged and ErrConnected is returned. the bytes are encoded as base64.
func (e *Edge) SetValueBytes(val []byte) error {
if len(e.nq.ObjectId) > 0 {
Expand Down
15 changes: 8 additions & 7 deletions client/mutations.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ import (
)

var (
ErrConnected = errors.New("Edge already connected to another node.")
ErrValue = errors.New("Edge already has a value.")
ErrEmptyXid = errors.New("Empty XID node.")
ErrInvalidType = errors.New("Invalid value type")
ErrEmptyVar = errors.New("Empty variable name.")
ErrNotConnected = errors.New("Edge needs to be connected to another node or a value.")
emptyEdge Edge
ErrConnected = errors.New("Edge already connected to another node.")
ErrValue = errors.New("Edge already has a value.")
ErrEmptyXid = errors.New("Empty XID node.")
ErrInvalidType = errors.New("Invalid value type")
ErrEmptyVar = errors.New("Empty variable name.")
ErrNotConnected = errors.New("Edge needs to be connected to another node or a value.")
ErrInvalidSubject = errors.New("Edge should have one of Subject/SubjectVar set.")
emptyEdge Edge
)

// BatchMutationOptions sets the clients batch mode to Pending number of buffers each of Size.
Expand Down
39 changes: 33 additions & 6 deletions client/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,12 @@ func setField(val reflect.Value, value *protos.Value, field reflect.StructField)
}

func unmarshal(n *protos.Node, typ reflect.Type) (reflect.Value, error) {
fmap := fieldMap(typ)
var val reflect.Value
if typ.Kind() == reflect.Array {
return val, fmt.Errorf("Arrays are not supported. Try using a slice.")
}

fmap := fieldMap(typ)
if typ.Kind() == reflect.Ptr {
// We got a pointer, lets set val to a settable type.
val = reflect.New(typ.Elem()).Elem()
Expand Down Expand Up @@ -210,21 +213,42 @@ func fieldMap(typ reflect.Type) map[string]reflect.StructField {
return fmap
}

// Unmarshal is used to unpack a query response into a custom struct. The
// response from Dgraph.Run (a *protos.Response) has 4 fields, L(Latency),
func resetStruct(t reflect.Type, v reflect.Value) {
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
ft := t.Field(i)
if !f.CanSet() {
continue
}
switch ft.Type.Kind() {
case reflect.Slice:
f.Set(reflect.MakeSlice(ft.Type, 0, 0))
case reflect.Struct:
resetStruct(ft.Type, f)
case reflect.Ptr:
fv := reflect.New(ft.Type.Elem())
resetStruct(ft.Type.Elem(), fv.Elem())
f.Set(fv)
default:
}
}
}

// Unmarshal is used to unpack a query response into a custom struct. The
// response from Dgraph.Run (a *protos.Response) has 4 fields, L(Latency),
// Schema, AssignedUids and N(Nodes). This function takes in the nodes part of
// the response and tries to unmarshal it into the given struct v.
//
// protos.Response.N is a slice of Nodes, one for each named query block in the
// request. Each node in that slice has attribute "_root_" and a child for
// request. Each node in that slice has attribute "_root_" and a child for
// each node returned as a result by that query block. For a response resp,
// and struct variable v, with a field tagged with the same name as a query
// block:
// Unmarshal(resp.N, s)
// will try to match named query blocks with tags in s and then unmarshall the
// the matched block into the matched fields of s.
//
// Unmarshal does not have to be called at resp.N. Clients can navigate to a
//
// Unmarshal does not have to be called at resp.N. Clients can navigate to a
// particular part of the response and unmarshal the children.
func Unmarshal(n []*protos.Node, v interface{}) error {
rv := reflect.ValueOf(v)
Expand All @@ -237,6 +261,9 @@ func Unmarshal(n []*protos.Node, v interface{}) error {
val.Kind())
}

// This is important so that all fields of the struct given by the user are reset.
resetStruct(val.Type(), val)

// Root can have multiple query blocks.
for _, node := range n {
for _, child := range node.Children {
Expand Down
2 changes: 2 additions & 0 deletions client_test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/p/
/w/
Loading