github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/go/ngql/query.go (about) 1 // Copyright 2017 Attic Labs, Inc. All rights reserved. 2 // Licensed under the Apache License, version 2.0: 3 // http://www.apache.org/licenses/LICENSE-2.0 4 5 package ngql 6 7 import ( 8 "context" 9 "encoding/json" 10 "io" 11 12 "github.com/attic-labs/graphql" 13 "github.com/attic-labs/graphql/gqlerrors" 14 "github.com/attic-labs/noms/go/d" 15 "github.com/attic-labs/noms/go/types" 16 ) 17 18 const ( 19 atKey = "at" 20 countKey = "count" 21 elementsKey = "elements" 22 entriesKey = "entries" 23 keyKey = "key" 24 keysKey = "keys" 25 rootKey = "root" 26 rootQueryKey = "Root" 27 scalarValue = "scalarValue" 28 sizeKey = "size" 29 targetHashKey = "targetHash" 30 targetValueKey = "targetValue" 31 throughKey = "through" 32 valueKey = "value" 33 valuesKey = "values" 34 vrwKey = "vrw" 35 ) 36 37 // NewRootQueryObject creates a "root" query object that can be used to 38 // traverse the value tree of rootValue. 39 func NewRootQueryObject(rootValue types.Value, tm *TypeMap) *graphql.Object { 40 tc := TypeConverter{*tm, DefaultNameFunc} 41 return tc.NewRootQueryObject(rootValue) 42 } 43 44 // NewRootQueryObject creates a "root" query object that can be used to 45 // traverse the value tree of rootValue. 46 func (tc *TypeConverter) NewRootQueryObject(rootValue types.Value) *graphql.Object { 47 rootNomsType := types.TypeOf(rootValue) 48 rootType := tc.NomsTypeToGraphQLType(rootNomsType) 49 50 return graphql.NewObject(graphql.ObjectConfig{ 51 Name: rootQueryKey, 52 Fields: graphql.Fields{ 53 rootKey: &graphql.Field{ 54 Type: rootType, 55 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 56 return MaybeGetScalar(rootValue), nil 57 }, 58 }, 59 }}) 60 } 61 62 // NewContext creates a new context.Context with the extra data added to it 63 // that is required by ngql. 64 func NewContext(vrw types.ValueReader) context.Context { 65 return context.WithValue(context.Background(), vrwKey, vrw) 66 } 67 68 // Query takes |rootValue|, builds a GraphQL scheme from rootValue.Type() and 69 // executes |query| against it, encoding the result to |w|. 70 func Query(rootValue types.Value, query string, vrw types.ValueReadWriter, w io.Writer) { 71 schemaConfig := graphql.SchemaConfig{} 72 tc := NewTypeConverter() 73 queryWithSchemaConfig(rootValue, query, schemaConfig, vrw, tc, w) 74 } 75 76 func queryWithSchemaConfig(rootValue types.Value, query string, schemaConfig graphql.SchemaConfig, vrw types.ValueReadWriter, tc *TypeConverter, w io.Writer) { 77 schemaConfig.Query = tc.NewRootQueryObject(rootValue) 78 schema, _ := graphql.NewSchema(schemaConfig) 79 ctx := NewContext(vrw) 80 81 r := graphql.Do(graphql.Params{ 82 Schema: schema, 83 RequestString: query, 84 Context: ctx, 85 }) 86 87 err := json.NewEncoder(w).Encode(r) 88 d.PanicIfError(err) 89 } 90 91 // Error writes an error as a GraphQL error to a writer. 92 func Error(err error, w io.Writer) { 93 r := graphql.Result{ 94 Errors: []gqlerrors.FormattedError{ 95 {Message: err.Error()}, 96 }, 97 } 98 99 jsonErr := json.NewEncoder(w).Encode(r) 100 d.PanicIfError(jsonErr) 101 }