CompleteObject builds a json GraphQL result object for the current query level. It returns a bracketed json object like { f1:..., f2:..., ... }. At present, it is only used for building custom results by: - Admin Server - @custom(http: {...}) query/mutation - @custom(dql: ...) queries fields are al
(
path []interface{},
fields []Field,
res map[string]interface{})
| 96 | // if "dob" were non-nullable (maybe it's type is DateTime!), then the result is |
| 97 | // nil and the error propagates to the enclosing level. |
| 98 | func CompleteObject( |
| 99 | path []interface{}, |
| 100 | fields []Field, |
| 101 | res map[string]interface{}) ([]byte, x.GqlErrorList) { |
| 102 | |
| 103 | var errs x.GqlErrorList |
| 104 | var buf bytes.Buffer |
| 105 | comma := "" |
| 106 | |
| 107 | // seenField keeps track of fields which have been seen as part of |
| 108 | // interface to avoid double entry in the resulting response |
| 109 | seenField := make(map[string]bool) |
| 110 | |
| 111 | x.Check2(buf.WriteRune('{')) |
| 112 | var dgraphTypes []string |
| 113 | if typename, ok := res[Typename].(string); ok && len(typename) > 0 { |
| 114 | // @custom(http: {...}) query/mutation results may return __typename in response for |
| 115 | // abstract fields, lets use that information if present. |
| 116 | dgraphTypes = []string{typename} |
| 117 | } else if dgTypeVals, ok := res["dgraph.type"].([]interface{}); ok { |
| 118 | // @custom(dql: ...) query results may return dgraph.type in response for abstract fields |
| 119 | for _, val := range dgTypeVals { |
| 120 | if typename, ok = val.(string); ok { |
| 121 | dgraphTypes = append(dgraphTypes, typename) |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | for _, f := range fields { |
| 127 | if f.SkipField(dgraphTypes, seenField) { |
| 128 | continue |
| 129 | } |
| 130 | |
| 131 | x.Check2(buf.WriteString(comma)) |
| 132 | f.CompleteAlias(&buf) |
| 133 | |
| 134 | val := res[f.RemoteResponseName()] |
| 135 | if f.RemoteResponseName() == Typename { |
| 136 | // From GraphQL spec: |
| 137 | // https://graphql.github.io/graphql-spec/June2018/#sec-Type-Name-Introspection |
| 138 | // "GraphQL supports type name introspection at any point within a query by the |
| 139 | // meta‐field __typename: String! when querying against any Object, Interface, |
| 140 | // or Union. It returns the name of the object type currently being queried." |
| 141 | |
| 142 | // If we have __typename information, we will use that to figure out the type |
| 143 | // otherwise we will get it from the schema. |
| 144 | val = f.TypeName(dgraphTypes) |
| 145 | } |
| 146 | |
| 147 | // Check that data should be of list type when we expect f.Type().ListType() to be non-nil. |
| 148 | if val != nil && f.Type().ListType() != nil { |
| 149 | switch val.(type) { |
| 150 | case []interface{}, []map[string]interface{}: |
| 151 | default: |
| 152 | // We were expecting a list but got a value which wasn't a list. Lets return an |
| 153 | // error. |
| 154 | return nil, x.GqlErrorList{f.GqlErrorf(path, ErrExpectedList)} |
| 155 | } |