From ada9ab0385a730c701bc318cbbfed7b409e36d93 Mon Sep 17 00:00:00 2001
From: Manish R Jain <manishrjain@gmail.com>
Date: Wed, 13 Apr 2016 16:17:27 +1000
Subject: [PATCH] Bug Fix: Parse RDFs when _uid_:0xid is provided.

---
 rdf/parse.go      |  3 +--
 rdf/parse_test.go | 13 +++++++++++++
 rdf/state.go      | 40 ++++++++++++++++++++++++++++++++++------
 server/main.go    | 12 +++++++-----
 4 files changed, 55 insertions(+), 13 deletions(-)

diff --git a/rdf/parse.go b/rdf/parse.go
index 4b477975..f8501c4e 100644
--- a/rdf/parse.go
+++ b/rdf/parse.go
@@ -69,8 +69,7 @@ func (nq NQuad) ToEdge() (result x.DirectedEdge, rerr error) {
 }
 
 func toUid(xid string, xidToUid map[string]uint64) (uid uint64, rerr error) {
-	id, present := xidToUid[xid]
-	if present {
+	if id, present := xidToUid[xid]; present {
 		return id, nil
 	}
 
diff --git a/rdf/parse_test.go b/rdf/parse_test.go
index f2c0c8fd..fcba4a7b 100644
--- a/rdf/parse_test.go
+++ b/rdf/parse_test.go
@@ -44,6 +44,15 @@ var testNQuads = []struct {
 			ObjectValue: nil,
 		},
 	},
+	{
+		input: `_uid_:0x01 <predicate> <object_id> .`,
+		nq: NQuad{
+			Subject:     "_uid_:0x01",
+			Predicate:   "predicate",
+			ObjectId:    "object_id",
+			ObjectValue: nil,
+		},
+	},
 	{
 		input: `_:alice <follows> _:bob0 .`,
 		nq: NQuad{
@@ -106,6 +115,10 @@ var testNQuads = []struct {
 		input:  "_:alice knows .",
 		hasErr: true,
 	},
+	{
+		input:  "_uid_: 0x01 <knows> <something> .",
+		hasErr: true,
+	},
 	{
 		input:  `_:alice "knows" stuff .`,
 		hasErr: true,
diff --git a/rdf/state.go b/rdf/state.go
index 04e18fbb..78b3a7e0 100644
--- a/rdf/state.go
+++ b/rdf/state.go
@@ -19,6 +19,9 @@
 package rdf
 
 import (
+	"strconv"
+	"strings"
+
 	"github.com/dgraph-io/dgraph/lex"
 	"github.com/dgraph-io/dgraph/x"
 )
@@ -120,19 +123,38 @@ func lexUntilClosing(l *lex.Lexer, styp lex.ItemType,
 	return l.Errorf("Invalid character %v found for itemType: %v", r, styp)
 }
 
+func lexUidNode(l *lex.Lexer, styp lex.ItemType, sfn lex.StateFn) lex.StateFn {
+
+	l.AcceptUntil(isSpace)
+	r := l.Peek()
+	if r == lex.EOF {
+		return l.Errorf("Unexpected end of uid subject")
+	}
+	in := l.Input[l.Start:l.Pos]
+	if !strings.HasPrefix(in, "_uid_:") {
+		return l.Errorf("Expected _uid_: Found: %v", l.Input[l.Start:l.Pos])
+	}
+	if _, err := strconv.ParseUint(in[6:], 0, 64); err != nil {
+		return l.Errorf("Unable to convert '%v' to UID", in[6:])
+	}
+
+	if isSpace(r) {
+		l.Emit(styp)
+		return sfn
+	}
+	return l.Errorf(
+		"Invalid character %v found for UID node itemType: %v", r, styp)
+}
+
 // Assumes that the current rune is '_'.
 func lexBlankNode(l *lex.Lexer, styp lex.ItemType,
 	sfn lex.StateFn) lex.StateFn {
 
-	r := l.Next()
-	if r != ':' {
-		return l.Errorf("Invalid input RDF Blank Node found at pos: %v", r)
-	}
 	// RDF Blank Node.
 	// TODO: At some point do checkings based on the guidelines. For now,
 	// just accept everything until space.
 	l.AcceptUntil(isSpace)
-	r = l.Peek()
+	r := l.Peek()
 	if r == lex.EOF {
 		return l.Errorf("Unexpected end of subject")
 	}
@@ -152,7 +174,13 @@ func lexSubject(l *lex.Lexer) lex.StateFn {
 
 	if r == '_' {
 		l.Depth += 1
-		return lexBlankNode(l, itemSubject, lexText)
+		r = l.Next()
+		if r == 'u' {
+			return lexUidNode(l, itemSubject, lexText)
+
+		} else if r == ':' {
+			return lexBlankNode(l, itemSubject, lexText)
+		} // else go to error
 	}
 
 	return l.Errorf("Invalid character during lexSubject: %v", r)
diff --git a/server/main.go b/server/main.go
index 8a7c90dd..10e4a77c 100644
--- a/server/main.go
+++ b/server/main.go
@@ -80,16 +80,18 @@ func mutationHandler(mu *gql.Mutation) error {
 
 	xidToUid := make(map[string]uint64)
 	for _, nq := range nquads {
-		if !strings.HasPrefix("_uid_:", nq.Subject) {
+		if !strings.HasPrefix(nq.Subject, "_uid_:") {
 			xidToUid[nq.Subject] = 0
 		}
-		if !strings.HasPrefix("_uid_:", nq.ObjectId) {
+		if len(nq.ObjectId) > 0 && !strings.HasPrefix(nq.ObjectId, "_uid_:") {
 			xidToUid[nq.ObjectId] = 0
 		}
 	}
-	if err := worker.GetOrAssignUidsOverNetwork(&xidToUid); err != nil {
-		glog.WithError(err).Error("GetOrAssignUidsOverNetwork")
-		return err
+	if len(xidToUid) > 0 {
+		if err := worker.GetOrAssignUidsOverNetwork(&xidToUid); err != nil {
+			glog.WithError(err).Error("GetOrAssignUidsOverNetwork")
+			return err
+		}
 	}
 
 	var edges []x.DirectedEdge
-- 
GitLab