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

Store and query types. #3018

Merged
merged 14 commits into from
Mar 11, 2019
Merged
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
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