Skip to content

Commit

Permalink
Store and query types. (#3018)
Browse files Browse the repository at this point in the history
This change adds the ability to store the types and query them similarly
to how the schema is currently being parsed.
  • Loading branch information
martinmr authored Mar 11, 2019
1 parent 8534ffb commit d5d4883
Show file tree
Hide file tree
Showing 16 changed files with 772 additions and 261 deletions.
75 changes: 68 additions & 7 deletions edgraph/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/dgraph-io/dgraph/protos/pb"
"github.com/dgraph-io/dgraph/query"
"github.com/dgraph-io/dgraph/schema"
"github.com/dgraph-io/dgraph/types"
"github.com/dgraph-io/dgraph/types/facets"
"github.com/dgraph-io/dgraph/worker"
"github.com/dgraph-io/dgraph/x"
Expand Down Expand Up @@ -365,6 +366,7 @@ func (s *Server) Alter(ctx context.Context, op *api.Operation) (*api.Payload, er
glog.Infof("Got schema: %+v\n", result.Schemas)
// TODO: Maybe add some checks about the schema.
m.Schema = result.Schemas
m.Types = result.Types
_, err = query.ApplyMutations(ctx, m)
return empty, err
}
Expand Down Expand Up @@ -595,18 +597,27 @@ func (s *Server) doQuery(ctx context.Context, req *api.Request) (resp *api.Respo
}

// Core processing happens here.
var er query.ExecuteResult
var er query.ExecutionResult
if er, err = queryRequest.Process(ctx); err != nil {
return resp, x.Wrap(err)
}
resp.Schema = er.SchemaNode

var js []byte
if len(resp.Schema) > 0 {
sort.Slice(resp.Schema, func(i, j int) bool {
return resp.Schema[i].Predicate < resp.Schema[j].Predicate
if len(er.SchemaNode) > 0 || len(er.Types) > 0 {
sort.Slice(er.SchemaNode, func(i, j int) bool {
return er.SchemaNode[i].Predicate < er.SchemaNode[j].Predicate
})
sort.Slice(er.Types, func(i, j int) bool {
return er.Types[i].TypeName < er.Types[j].TypeName
})
js, err = json.Marshal(map[string]interface{}{"schema": resp.Schema})

respMap := make(map[string]interface{})
if len(er.SchemaNode) > 0 {
respMap["schema"] = er.SchemaNode
}
if len(er.Types) > 0 {
respMap["types"] = formatTypes(er.Types)
}
js, err = json.Marshal(respMap)
} else {
js, err = query.ToJson(&l, er.Subgraphs)
}
Expand Down Expand Up @@ -871,3 +882,53 @@ func validatePredName(name string) error {
}
return nil
}

// formatField takes a SchemaUpdate representing a field in a type and converts
// it into a map containing keys for the type name and the type.
func formatField(field *pb.SchemaUpdate) map[string]string {
fieldMap := make(map[string]string)
fieldMap["name"] = field.Predicate
typ := ""
if field.List {
typ += "["
}

if field.ValueType == pb.Posting_OBJECT {
typ += field.ObjectTypeName
} else {
typeId := types.TypeID(field.ValueType)
typ += typeId.Name()
}

if field.NonNullable {
typ += "!"
}
if field.List {
typ += "]"
}
if field.NonNullableList {
typ += "!"
}
fieldMap["type"] = typ

return fieldMap
}

// formatTypes takes a list of TypeUpdates and converts them in to a list of
// maps in a format that is human-readable to be marshaled into JSON.
func formatTypes(types []*pb.TypeUpdate) []map[string]interface{} {
var res []map[string]interface{}
for _, typ := range types {
typeMap := make(map[string]interface{})
typeMap["name"] = typ.TypeName
typeMap["fields"] = make([]map[string]string, 0)

for _, field := range typ.Fields {
fieldMap := formatField(field)
typeMap["fields"] = append(typeMap["fields"].([]map[string]string), fieldMap)
}

res = append(res, typeMap)
}
return res
}
31 changes: 23 additions & 8 deletions gql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -884,14 +884,19 @@ func parseListItemNames(it *lex.ItemIterator) ([]string, error) {
return items, it.Errorf("Expecting ] to end list but none was found")
}

// parses till rightround is found
func parseSchemaPredicates(it *lex.ItemIterator, s *pb.SchemaRequest) error {
// pred should be followed by colon
// parseSchemaPredsOrTypes parses till rightround is found
func parseSchemaPredsOrTypes(it *lex.ItemIterator, s *pb.SchemaRequest) error {
// pred or type should be followed by colon
it.Next()
item := it.Item()
if item.Typ != itemName && item.Val != "pred" {
if item.Typ != itemName && !(item.Val == "pred" || item.Val == "type") {
return item.Errorf("Invalid schema block")
}
parseTypes := false
if item.Val == "type" {
parseTypes = true
}

it.Next()
item = it.Item()
if item.Typ != itemColon {
Expand All @@ -902,12 +907,22 @@ func parseSchemaPredicates(it *lex.ItemIterator, s *pb.SchemaRequest) error {
it.Next()
item = it.Item()
if item.Typ == itemName {
s.Predicates = append(s.Predicates, item.Val)
if parseTypes {
s.Types = append(s.Types, item.Val)
} else {
s.Predicates = append(s.Predicates, item.Val)
}
} else if item.Typ == itemLeftSquare {
var err error
if s.Predicates, err = parseListItemNames(it); err != nil {
names, err := parseListItemNames(it)
if err != nil {
return err
}

if parseTypes {
s.Types = names
} else {
s.Predicates = names
}
} else {
return item.Errorf("Invalid schema block")
}
Expand Down Expand Up @@ -952,7 +967,7 @@ func getSchema(it *lex.ItemIterator) (*pb.SchemaRequest, error) {
return nil, item.Errorf("Too many left rounds in schema block")
}
leftRoundSeen = true
if err := parseSchemaPredicates(it, &s); err != nil {
if err := parseSchemaPredsOrTypes(it, &s); err != nil {
return nil, err
}
default:
Expand Down
27 changes: 27 additions & 0 deletions gql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,33 @@ func TestParseSchemaAndQuery(t *testing.T) {
require.Contains(t, err.Error(), "Schema block is not allowed with query block")
}

func TestParseSchemaType(t *testing.T) {
query := `
schema (type: Person) {
}
`
res, err := Parse(Request{Str: query})
require.NoError(t, err)
require.Equal(t, len(res.Schema.Predicates), 0)
require.Equal(t, len(res.Schema.Types), 1)
require.Equal(t, res.Schema.Types[0], "Person")
require.Equal(t, len(res.Schema.Fields), 0)
}

func TestParseSchemaTypeMulti(t *testing.T) {
query := `
schema (type: [Person, Animal]) {
}
`
res, err := Parse(Request{Str: query})
require.NoError(t, err)
require.Equal(t, len(res.Schema.Predicates), 0)
require.Equal(t, len(res.Schema.Types), 2)
require.Equal(t, res.Schema.Types[0], "Person")
require.Equal(t, res.Schema.Types[1], "Animal")
require.Equal(t, len(res.Schema.Fields), 0)
}

func TestParseSchemaError(t *testing.T) {
query := `
schema () {
Expand Down
3 changes: 3 additions & 0 deletions protos/pb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ message Mutations {
repeated SchemaUpdate schema = 4;
bool drop_all = 5;
bool ignore_index_conflict = 6;
repeated TypeUpdate types = 7;
}

message Snapshot {
Expand Down Expand Up @@ -316,6 +317,8 @@ message SchemaRequest {
repeated string predicates = 2;
// fields can be on of type, index, reverse or tokenizer
repeated string fields = 3;

repeated string types = 4;
}

message SchemaResult {
Expand Down
Loading

0 comments on commit d5d4883

Please sign in to comment.