140 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package generator
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/jhump/protoreflect/desc"
 | |
| 	"github.com/vektah/gqlparser/v2/ast"
 | |
| )
 | |
| 
 | |
| type Registry interface {
 | |
| 	FindMethodByName(op ast.Operation, name string) *desc.MethodDescriptor
 | |
| 	FindObjectByName(name string) *desc.MessageDescriptor
 | |
| 
 | |
| 	// FindObjectByFullyQualifiedName TODO maybe find a better way to get ast definition
 | |
| 	FindObjectByFullyQualifiedName(fqn string) (*desc.MessageDescriptor, *ast.Definition)
 | |
| 
 | |
| 	// FindFieldByName given the proto Descriptor and the graphql field name get the the proto FieldDescriptor
 | |
| 	FindFieldByName(msg desc.Descriptor, name string) *desc.FieldDescriptor
 | |
| 
 | |
| 	// FindUnionFieldByMessageFQNAndName given the proto Descriptor and the graphql field name get the the proto FieldDescriptor
 | |
| 	FindUnionFieldByMessageFQNAndName(fqn, name string) *desc.FieldDescriptor
 | |
| 
 | |
| 	FindGraphqlFieldByProtoField(msg *ast.Definition, name string) *ast.FieldDefinition
 | |
| }
 | |
| 
 | |
| func NewRegistry(files SchemaDescriptorList) Registry {
 | |
| 	v := &repository{
 | |
| 		mu:                       &sync.RWMutex{},
 | |
| 		methodsByName:            map[ast.Operation]map[string]*desc.MethodDescriptor{},
 | |
| 		objectsByName:            map[string]*desc.MessageDescriptor{},
 | |
| 		objectsByFQN:             map[string]*ObjectDescriptor{},
 | |
| 		graphqlFieldsByName:      map[desc.Descriptor]map[string]*desc.FieldDescriptor{},
 | |
| 		graphqlUnionFieldsByName: map[string]map[string]*desc.FieldDescriptor{},
 | |
| 		protoFieldsByName:        map[*ast.Definition]map[string]*ast.FieldDefinition{},
 | |
| 	}
 | |
| 	for _, f := range files {
 | |
| 		v.methodsByName[ast.Mutation] = map[string]*desc.MethodDescriptor{}
 | |
| 		for _, m := range f.GetMutation().Methods() {
 | |
| 			v.methodsByName[ast.Mutation][m.Name] = m.MethodDescriptor
 | |
| 		}
 | |
| 		v.methodsByName[ast.Query] = map[string]*desc.MethodDescriptor{}
 | |
| 		for _, m := range f.GetQuery().Methods() {
 | |
| 			v.methodsByName[ast.Query][m.Name] = m.MethodDescriptor
 | |
| 		}
 | |
| 		v.methodsByName[ast.Subscription] = map[string]*desc.MethodDescriptor{}
 | |
| 		for _, m := range f.GetSubscription().Methods() {
 | |
| 			v.methodsByName[ast.Subscription][m.Name] = m.MethodDescriptor
 | |
| 		}
 | |
| 	}
 | |
| 	for _, f := range files {
 | |
| 		for _, m := range f.Objects() {
 | |
| 			switch m.Kind {
 | |
| 			case ast.Union:
 | |
| 				fqn := m.Descriptor.GetParent().GetFullyQualifiedName()
 | |
| 				if _, ok := v.graphqlUnionFieldsByName[fqn]; !ok {
 | |
| 					v.graphqlUnionFieldsByName[fqn] = map[string]*desc.FieldDescriptor{}
 | |
| 				}
 | |
| 				for _, tt := range m.GetTypes() {
 | |
| 					for _, f := range tt.GetFields() {
 | |
| 						v.graphqlUnionFieldsByName[fqn][f.Name] = f.FieldDescriptor
 | |
| 					}
 | |
| 				}
 | |
| 			case ast.Object:
 | |
| 				v.protoFieldsByName[m.Definition] = map[string]*ast.FieldDefinition{}
 | |
| 				for _, f := range m.GetFields() {
 | |
| 					if f.FieldDescriptor != nil {
 | |
| 						v.protoFieldsByName[m.Definition][f.FieldDescriptor.GetName()] = f.FieldDefinition
 | |
| 					}
 | |
| 				}
 | |
| 			case ast.InputObject:
 | |
| 				v.graphqlFieldsByName[m.Descriptor] = map[string]*desc.FieldDescriptor{}
 | |
| 				for _, f := range m.GetFields() {
 | |
| 					v.graphqlFieldsByName[m.Descriptor][f.Name] = f.FieldDescriptor
 | |
| 				}
 | |
| 			}
 | |
| 			switch msgDesc := m.Descriptor.(type) {
 | |
| 			case *desc.MessageDescriptor:
 | |
| 				v.objectsByFQN[m.GetFullyQualifiedName()] = m
 | |
| 				v.objectsByName[m.Name] = msgDesc
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return v
 | |
| }
 | |
| 
 | |
| type repository struct {
 | |
| 	files SchemaDescriptorList
 | |
| 	mu    *sync.RWMutex
 | |
| 
 | |
| 	methodsByName            map[ast.Operation]map[string]*desc.MethodDescriptor
 | |
| 	objectsByName            map[string]*desc.MessageDescriptor
 | |
| 	objectsByFQN             map[string]*ObjectDescriptor
 | |
| 	graphqlFieldsByName      map[desc.Descriptor]map[string]*desc.FieldDescriptor
 | |
| 	protoFieldsByName        map[*ast.Definition]map[string]*ast.FieldDefinition
 | |
| 	graphqlUnionFieldsByName map[string]map[string]*desc.FieldDescriptor
 | |
| }
 | |
| 
 | |
| func (r repository) FindMethodByName(op ast.Operation, name string) *desc.MethodDescriptor {
 | |
| 	r.mu.RLock()
 | |
| 	defer r.mu.RUnlock()
 | |
| 	m, _ := r.methodsByName[op][name]
 | |
| 	return m
 | |
| }
 | |
| 
 | |
| func (r repository) FindObjectByName(name string) *desc.MessageDescriptor {
 | |
| 	r.mu.RLock()
 | |
| 	defer r.mu.RUnlock()
 | |
| 	o, _ := r.objectsByName[name]
 | |
| 	return o
 | |
| }
 | |
| 
 | |
| func (r repository) FindObjectByFullyQualifiedName(fqn string) (*desc.MessageDescriptor, *ast.Definition) {
 | |
| 	r.mu.RLock()
 | |
| 	defer r.mu.RUnlock()
 | |
| 	o, _ := r.objectsByFQN[fqn]
 | |
| 	msg, _ := o.Descriptor.(*desc.MessageDescriptor)
 | |
| 	return msg, o.Definition
 | |
| }
 | |
| 
 | |
| func (r repository) FindFieldByName(msg desc.Descriptor, name string) *desc.FieldDescriptor {
 | |
| 	r.mu.RLock()
 | |
| 	defer r.mu.RUnlock()
 | |
| 	f, _ := r.graphqlFieldsByName[msg][name]
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (r repository) FindUnionFieldByMessageFQNAndName(fqn, name string) *desc.FieldDescriptor {
 | |
| 	r.mu.RLock()
 | |
| 	defer r.mu.RUnlock()
 | |
| 	f, _ := r.graphqlUnionFieldsByName[fqn][name]
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (r repository) FindGraphqlFieldByProtoField(msg *ast.Definition, name string) *ast.FieldDefinition {
 | |
| 	r.mu.RLock()
 | |
| 	defer r.mu.RUnlock()
 | |
| 	f, _ := r.protoFieldsByName[msg][name]
 | |
| 	return f
 | |
| }
 |