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

Parser for type declaration. #2950

Merged
merged 11 commits into from
Feb 5, 2019
4 changes: 2 additions & 2 deletions dgraph/cmd/bulk/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ func readSchema(filename string) []*pb.SchemaUpdate {
buf, err := ioutil.ReadAll(r)
x.Check(err)

initialSchema, err := schema.Parse(string(buf))
result, err := schema.Parse(string(buf))
x.Check(err)
return initialSchema
return result.Schemas
}

func findDataFiles(dir string, ext string) []string {
Expand Down
4 changes: 2 additions & 2 deletions edgraph/access_ee.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,11 +462,11 @@ func authorizeAlter(ctx context.Context, op *api.Operation) error {
return nil
}

updates, err := schema.Parse(op.Schema)
result, err := schema.Parse(op.Schema)
if err != nil {
return err
}
for _, update := range updates {
for _, update := range result.Schemas {
if err := authorizePredicate(groupIds, update.Predicate, acl.Modify); err != nil {
return status.Error(codes.PermissionDenied,
fmt.Sprintf("unauthorized to alter the predicate: %v", err))
Expand Down
6 changes: 3 additions & 3 deletions edgraph/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,13 @@ func (s *Server) Alter(ctx context.Context, op *api.Operation) (*api.Payload, er
return empty, err
}

updates, err := schema.Parse(op.Schema)
result, err := schema.Parse(op.Schema)
if err != nil {
return empty, err
}
glog.Infof("Got schema: %+v\n", updates)
glog.Infof("Got schema: %+v\n", result.Schemas)
// TODO: Maybe add some checks about the schema.
m.Schema = updates
m.Schema = result.Schemas
_, err = query.ApplyMutations(ctx, m)
return empty, err
}
Expand Down
12 changes: 11 additions & 1 deletion protos/pb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ message Posting {
UID = 7;
PASSWORD = 8;
STRING = 9;

OBJECT = 10;
}
ValType val_type = 3;
enum PostingType {
Expand Down Expand Up @@ -337,11 +337,21 @@ message SchemaUpdate {
bool upsert = 8;
bool lang = 9;

// Fields required for type system.
bool non_nullable = 10;
bool non_nullable_list = 11;
string object_type_name = 12;

// Deleted field:
reserved 7;
reserved "explicit";
}

message TypeUpdate {
string type_name = 1;
repeated SchemaUpdate fields = 2;
}

// Bulk loader proto.
message MapEntry {
bytes key = 1;
Expand Down
833 changes: 600 additions & 233 deletions protos/pb/pb.pb.go

Large diffs are not rendered by default.

154 changes: 145 additions & 9 deletions schema/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ func ParseBytes(s []byte, gid uint32) (rerr error) {
reset()
}
pstate.DeleteAll()
updates, err := Parse(string(s))
result, err := Parse(string(s))
if err != nil {
return err
}

for _, update := range updates {
for _, update := range result.Schemas {
State().Set(update.Predicate, *update)
}
State().Set("_predicate_", pb.SchemaUpdate{
Expand Down Expand Up @@ -295,36 +295,172 @@ func resolveTokenizers(updates []*pb.SchemaUpdate) error {
return nil
}

func parseTypeDeclaration(it *lex.ItemIterator) (*pb.TypeUpdate, error) {
// Iterator is currently on the token corresponding to the keyword type.
// Call Next to land on the type name.
it.Next()
typeUpdate := &pb.TypeUpdate{TypeName: it.Item().Val}

// Call next again to skip the { character.
it.Next()

var fields []*pb.SchemaUpdate
for {
item := it.Item()
switch item.Typ {
case itemRightCurl:
it.Next()
if it.Item().Typ != itemNewLine {
return nil, x.Errorf("Expected new line after type declaration. Got %v",
it.Item().Val)
}

typeUpdate.Fields = fields
return typeUpdate, nil
case itemText:
field, err := parseTypeField(it)
if err != nil {
return nil, err
}
fields = append(fields, field)
default:
it.Next()
}
}
}

func parseTypeField(it *lex.ItemIterator) (*pb.SchemaUpdate, error) {
field := &pb.SchemaUpdate{Predicate: it.Item().Val}
list := false

it.Next()
if it.Item().Typ != itemColon {
return nil, x.Errorf("Missing colon in type declaration. Got %v", it.Item().Val)
}

it.Next()
if it.Item().Typ == itemLeftSquare {
list = true
it.Next()
}

if it.Item().Typ != itemText {
return nil, x.Errorf("Missing field type in type declaration. Got %v", it.Item().Val)
}
typ := getType(it.Item().Val)
field.ValueType = typ
if typ == pb.Posting_OBJECT {
field.ObjectTypeName = it.Item().Val
}

it.Next()
if it.Item().Typ == itemExclamationMark {
field.NonNullable = true
it.Next()
}

if list {
if it.Item().Typ != itemRightSquare {
return nil, x.Errorf("Expected matching square bracket. Got %v", it.Item().Val)
}
field.List = true
it.Next()

if it.Item().Typ == itemExclamationMark {
field.NonNullableList = true
it.Next()
}
}

if it.Item().Typ != itemNewLine {
return nil, x.Errorf("Expected new line after field declaration. Got %v", it.Item().Val)
}

it.Next()
return field, nil
}

func getType(typeName string) pb.Posting_ValType {
typ, ok := types.TypeForName(strings.ToLower(typeName))
if ok {
return pb.Posting_ValType(typ)
}

return pb.Posting_OBJECT
}

// SchemasAndTypes represents the parsed schema and type updates.
type SchemasAndTypes struct {
Schemas []*pb.SchemaUpdate
Types []*pb.TypeUpdate
}

func isTypeDeclaration(item lex.Item, it *lex.ItemIterator) bool {
if item.Val != "type" {
return false
}

nextItems, err := it.Peek(2)
if err != nil || len(nextItems) != 2 {
return false
}

if nextItems[0].Typ != itemText {
return false
}

if nextItems[1].Typ != itemLeftCurl {
return false
}

return true
}

// Parse parses a schema string and returns the schema representation for it.
func Parse(s string) ([]*pb.SchemaUpdate, error) {
func Parse(s string) (SchemasAndTypes, error) {
var emptyResult SchemasAndTypes
var result SchemasAndTypes
var schemas []*pb.SchemaUpdate
var types []*pb.TypeUpdate

l := lex.NewLexer(s)
l.Run(lexText)
if err := l.ValidateResult(); err != nil {
return nil, err
return emptyResult, err
}
it := l.NewIterator()
for it.Next() {
item := it.Item()
switch item.Typ {
case lex.ItemEOF:
if err := resolveTokenizers(schemas); err != nil {
return nil, x.Wrapf(err, "failed to enrich schema")
return emptyResult, x.Wrapf(err, "failed to enrich schema")
}
return schemas, nil
result.Schemas = schemas
result.Types = types
return result, nil

case itemText:
if isTypeDeclaration(item, it) {
typeUpdate, err := parseTypeDeclaration(it)
if err != nil {
return emptyResult, err
}
types = append(types, typeUpdate)
continue
}

schema, err := parseScalarPair(it, item.Val)
if err != nil {
return nil, err
return emptyResult, err
}
schemas = append(schemas, schema)
case itemNewLine:
// pass empty line

default:
return nil, x.Errorf("Unexpected token: %v while parsing schema", item)
return emptyResult, x.Errorf("Unexpected token: %v while parsing schema", item)
}
}
return nil, x.Errorf("Shouldn't reach here")
return emptyResult, x.Errorf("Shouldn't reach here")
}
Loading