• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dgraph-io / dgraph / 5228265546

10 Jun 2023 05:08AM UTC coverage: 67.303% (+0.07%) from 67.23%
5228265546

push

web-flow
Merge dba1461bb into ab3769797

16 of 16 new or added lines in 2 files covered. (100.0%)

58428 of 86814 relevant lines covered (67.3%)

2257715.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.13
/query/outputnode.go
1
/*
2
 * Copyright 2017-2023 Dgraph Labs, Inc. and Contributors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package query
18

19
import (
20
        "bytes"
21
        "context"
22
        "encoding/binary"
23
        "encoding/json"
24
        "fmt"
25
        "math"
26
        "strconv"
27
        "strings"
28
        "sync"
29
        "time"
30
        "unicode/utf8"
31
        "unsafe"
32

33
        "github.com/golang/glog"
34
        "github.com/pkg/errors"
35
        "github.com/twpayne/go-geom"
36
        "github.com/twpayne/go-geom/encoding/geojson"
37

38
        "github.com/dgraph-io/dgo/v230/protos/api"
39
        "github.com/dgraph-io/dgraph/algo"
40
        gqlSchema "github.com/dgraph-io/dgraph/graphql/schema"
41
        "github.com/dgraph-io/dgraph/protos/pb"
42
        "github.com/dgraph-io/dgraph/task"
43
        "github.com/dgraph-io/dgraph/types"
44
        "github.com/dgraph-io/dgraph/types/facets"
45
        "github.com/dgraph-io/dgraph/x"
46
        "github.com/dgraph-io/ristretto/z"
47
)
48

49
// ToJson converts the list of subgraph into a JSON response by calling toFastJSON.
50
func ToJson(ctx context.Context, l *Latency, sgl []*SubGraph, field gqlSchema.Field) ([]byte,
51
        error) {
26,859✔
52
        sgr := &SubGraph{}
26,859✔
53
        for _, sg := range sgl {
61,411✔
54
                if sg.Params.Alias == "var" || sg.Params.Alias == "shortest" {
40,560✔
55
                        continue
6,008✔
56
                }
57
                if sg.Params.GetUid {
28,554✔
58
                        sgr.Params.GetUid = true
10✔
59
                }
10✔
60
                sgr.Children = append(sgr.Children, sg)
28,544✔
61
        }
62
        data, err := sgr.toFastJSON(ctx, l, field)
26,859✔
63

26,859✔
64
        // don't log or wrap GraphQL errors
26,859✔
65
        if x.IsGqlErrorList(err) {
26,870✔
66
                return data, err
11✔
67
        }
11✔
68
        if err != nil {
26,850✔
69
                glog.Errorf("while running ToJson: %v\n", err)
2✔
70
        }
2✔
71
        return data, errors.Wrapf(err, "while running ToJson")
26,848✔
72
}
73

74
// We are capping maxEncoded size to 4GB, as grpc encoding fails
75
// for a response size > math.MaxUint32.
76
const maxEncodedSize = uint64(4 << 30)
77

78
type encoder struct {
79
        // attrMap has mapping of string predicates to uint16 ids.
80
        // For each predicate one unique id is assigned to save space.
81
        attrMap map[string]uint16
82
        // idSlice contains mapping from predicate id to predicate.
83
        idSlice []string
84
        // arena is used to store scalarVal for fastJsonNodes. Offset of scalarVal inside arena buffer
85
        // is stored in fastJsonNode meta.
86
        arena *arena
87
        // curSize is current estimated size of the encoded response. It should be less than actual
88
        // response size after encoding. If curSize exceeds a threshold size(maxEncodedSize), we return
89
        // query response with error saying response is too big. Currently curSize tracking has been
90
        // kept very simple. curSize is crossing threshold value or not is only checked at leaf(scalar)
91
        // nodes as of now. curSize is updated in following cases:
92
        // 1. By adding predicate len, while expanding it for an uid in preTraverse().
93
        // 2. By adding scalarVal len in setScalarVal function for a leaf(scalar) node.
94
        // TODO(Ashish): currently we are not including facets/groupby/aggregations fields in curSize
95
        // for simplicity. curSize can be made more accurate by adding these fields.
96
        curSize uint64
97

98
        // Allocator for nodes.
99
        alloc *z.Allocator
100

101
        // Cache uid attribute, which is very commonly used.
102
        uidAttr uint16
103

104
        // buf is the buffer which stores the JSON encoded response
105
        buf *bytes.Buffer
106
}
107

108
type node struct {
109
        // meta stores meta information for a fastJsonNode in an uint64. Layout is as follows.
110
        // Bytes 4-1 contains offset(uint32) for Arena.
111
        // Bytes 7-6 contains attr.
112
        // Bit MSB(first bit in Byte-8) contains list field value.
113
        // Bit SecondMSB(second bit in Byte-8) contains facetsParent field value.
114
        // Bit ThirdMSB(third bit in Byte-8) stores if the node contains uid value
115
        // Bit FourthMSB(fourth bit in Byte-8) stores if the order of node's children has been fixed.
116
        // Bit FifthMSB(fifth bit in Byte-8) stores if node contains value for a @custom GraphQL field.
117
        // Byte-5 is not getting used as of now.
118
        // |-----------------------------------------------------------------------------|
119
        // |             8              |    7   |    6   |    5   |  4  |  3  |  2 |  1 |
120
        // |-----------------------------------------------------------------------------|
121
        // | MSB - list                 |                 | Unused |                     |
122
        // | SecondMSB - facetsParent   |     Attr ID     | For    | Offset inside Arena |
123
        // | ThirdMSB - uid             |                 | Now    |                     |
124
        // | FourthMSB - Order Info     |                 |        |                     |
125
        // | FifthMSB - @custom GraphQL |                 |        |                     |
126
        // |-----------------------------------------------------------------------------|
127
        meta uint64
128

129
        next  *node
130
        child *node
131
}
132

133
var nodeSize = int(unsafe.Sizeof(node{}))
134

135
func newEncoder() *encoder {
26,863✔
136
        idSlice := make([]string, 1)
26,863✔
137

26,863✔
138
        a := (arenaPool.Get()).(*arena)
26,863✔
139
        a.reset()
26,863✔
140

26,863✔
141
        e := &encoder{
26,863✔
142
                attrMap: make(map[string]uint16),
26,863✔
143
                idSlice: idSlice,
26,863✔
144
                arena:   a,
26,863✔
145
                alloc:   z.NewAllocator(4<<10, "OutputNode.Encoder"),
26,863✔
146
                buf:     &bytes.Buffer{},
26,863✔
147
        }
26,863✔
148
        e.uidAttr = e.idForAttr("uid")
26,863✔
149
        return e
26,863✔
150
}
26,863✔
151

152
// Sort the given fastJson list
153
func (enc *encoder) MergeSort(headRef *fastJsonNode) {
506✔
154
        if headRef == nil || (*headRef).next == nil {
811✔
155
                return
305✔
156
        }
305✔
157

158
        var a, b fastJsonNode
201✔
159
        frontBackSplit(*headRef, &a, &b)
201✔
160
        enc.MergeSort(&a)
201✔
161
        enc.MergeSort(&b)
201✔
162
        *headRef = enc.mergeSortedLists(a, b)
201✔
163
}
164

165
func (enc *encoder) mergeSortedLists(a fastJsonNode, b fastJsonNode) fastJsonNode {
500✔
166
        var result fastJsonNode
500✔
167

500✔
168
        if a == nil {
575✔
169
                return b
75✔
170
        } else if b == nil {
626✔
171
                return a
126✔
172
        }
126✔
173

174
        if enc.less(a, b) {
453✔
175
                result = a
154✔
176
                result.next = enc.mergeSortedLists(a.next, b)
154✔
177
        } else {
299✔
178
                result = b
145✔
179
                result.next = enc.mergeSortedLists(a, b.next)
145✔
180
        }
145✔
181
        return result
299✔
182
}
183

184
func (enc *encoder) less(i fastJsonNode, j fastJsonNode) bool {
299✔
185
        attri := enc.getAttr(i)
299✔
186
        attrj := enc.getAttr(j)
299✔
187
        return strings.Compare(enc.attrForID(attri), enc.attrForID(attrj)) <= 0
299✔
188
}
299✔
189

190
func frontBackSplit(source fastJsonNode,
191
        frontRef *fastJsonNode, backRef *fastJsonNode) {
201✔
192
        slow := source
201✔
193
        fast := source.next
201✔
194

201✔
195
        for fast != nil {
435✔
196
                fast = fast.next
234✔
197
                if fast != nil {
314✔
198
                        slow = slow.next
80✔
199
                        fast = fast.next
80✔
200
                }
80✔
201
        }
202

203
        *frontRef = source
201✔
204
        *backRef = slow.next
201✔
205
        slow.next = nil
201✔
206
}
207

208
func (enc *encoder) idForAttr(attr string) uint16 {
558,724✔
209
        if attr == "uid" && enc.uidAttr > 0 {
565,423✔
210
                return enc.uidAttr
6,699✔
211
        }
6,699✔
212
        if id, ok := enc.attrMap[attr]; ok {
973,467✔
213
                return id
421,442✔
214
        }
421,442✔
215

216
        enc.idSlice = append(enc.idSlice, attr)
130,583✔
217
        enc.attrMap[attr] = uint16(len(enc.idSlice) - 1) // TODO(Ashish): check for overflow.
130,583✔
218
        return uint16(len(enc.idSlice) - 1)
130,583✔
219
}
220

221
func (enc *encoder) attrForID(id uint16) string {
97,042✔
222
        // For now we are not returning error from here.
97,042✔
223
        if id == 0 || id >= uint16(len(enc.idSlice)) {
97,042✔
224
                return ""
×
225
        }
×
226

227
        return enc.idSlice[id]
97,042✔
228
}
229

230
// makeScalarNode returns a fastJsonNode with all of its meta data, scalarVal populated.
231
func (enc *encoder) makeScalarNode(attr uint16, val []byte, list bool) (fastJsonNode, error) {
348,912✔
232
        fj := enc.newNode(attr)
348,912✔
233
        if err := enc.setScalarVal(fj, val); err != nil {
348,912✔
234
                return nil, err
×
235
        }
×
236
        enc.setList(fj, list)
348,912✔
237

348,912✔
238
        return fj, nil
348,912✔
239
}
240

241
func (enc *encoder) makeUidNode(attr uint16, uid uint64) (*node, error) {
10,931✔
242
        fj := enc.newNode(attr)
10,931✔
243
        fj.meta |= uidNodeBit
10,931✔
244

10,931✔
245
        var tmp [8]byte
10,931✔
246
        binary.BigEndian.PutUint64(tmp[:], uid)
10,931✔
247

10,931✔
248
        if err := enc.setScalarVal(fj, tmp[:]); err != nil {
10,931✔
249
                return nil, err
×
250
        }
×
251
        return fj, nil
10,931✔
252
}
253

254
// makeCustomNode returns a fastJsonNode that stores the given val for a @custom GraphQL field.
255
func (enc *encoder) makeCustomNode(attr uint16, val []byte) (fastJsonNode, error) {
285✔
256
        fj := enc.newNode(attr)
285✔
257
        if err := enc.setScalarVal(fj, val); err != nil {
285✔
258
                return nil, err
×
259
        }
×
260
        enc.setCustom(fj)
285✔
261

285✔
262
        return fj, nil
285✔
263
}
264

265
const (
266
        // Value with most significant bit set to 1.
267
        listBit = 1 << 63
268
        // Value with second most significant bit set to 1.
269
        facetsBit = 1 << 62
270
        // Value with third most significant bit set to 1.
271
        uidNodeBit = 1 << 61
272
        // Node has been visited for fixing the children order.
273
        visitedBit = 1 << 60
274
        // customBit is a value with fifth most significant bit set to 1. If a node has customBit set
275
        // in its meta, it means that node stores the value for a @custom GraphQL field.
276
        customBit = 1 << 59
277

278
        // Value with all bits set to 1 for bytes 7 and 6.
279
        setBytes76 = uint64(0x00FFFF0000000000)
280
        // Compliment value of setBytes76.
281
        unsetBytes76 = ^setBytes76
282
        // Value with all bits set to 1 for bytes 4 to 1.
283
        setBytes4321 = 0x00000000FFFFFFFF
284
)
285

286
// fastJsonNode represents node of a tree, which is formed to convert a subgraph into json response
287
// for a query. A fastJsonNode has following meta data:
288
//  1. Attr => predicate associated with this node.
289
//  2. ScalarVal => Any value associated with node, if it is a leaf node.
290
//  3. List => Stores boolean value, true if this node is part of list.
291
//  4. FacetsParent => Stores boolean value, true if this node is a facetsParent. facetsParent is
292
//     node which is parent for facets values for a scalar list predicate. Eg: node "city|country"
293
//     will have FacetsParent value as true.
294
//     {
295
//     "city": ["Bengaluru", "San Francisco"],
296
//     "city|country": {
297
//     "0": "india",
298
//     "1": "US"
299
//     }
300
//     }
301
//  5. Children(Attrs) => List of all children.
302
//  6. Visited => Stores boolen values, true if node has been visited for fixing children's order.
303
//
304
// All of the data for fastJsonNode tree is stored in encoder to optimise memory usage. fastJsonNode
305
// struct is pointer to node object. node object stores below information.
306
// 1. meta information.
307
// 2. Pointer to its first child.
308
// 3. Pointer to its sibling.
309
type fastJsonNode *node
310

311
// newNode returns a fastJsonNode with its attr set to attr,
312
// and all other meta set to their default value.
313
func (enc *encoder) newNode(attr uint16) fastJsonNode {
459,216✔
314
        b := enc.alloc.AllocateAligned(nodeSize)
459,216✔
315
        n := (*node)(unsafe.Pointer(&b[0]))
459,216✔
316
        enc.setAttr(n, attr)
459,216✔
317
        return n
459,216✔
318
}
459,216✔
319

320
func (enc *encoder) setAttr(fj fastJsonNode, attr uint16) {
510,943✔
321
        // There can be some cases where we change name of attr for fastJsoNode and
510,943✔
322
        // hence first clear the existing attr, then store new one.
510,943✔
323
        fj.meta &= unsetBytes76
510,943✔
324
        fj.meta |= (uint64(attr) << 40)
510,943✔
325
}
510,943✔
326

327
func (enc *encoder) setScalarVal(fj fastJsonNode, sv []byte) error {
360,130✔
328
        offset, err := enc.arena.put(sv)
360,130✔
329
        if err != nil {
360,130✔
330
                return err
×
331
        }
×
332
        fj.meta |= uint64(offset)
360,130✔
333

360,130✔
334
        // Also increase curSize.
360,130✔
335
        enc.curSize += uint64(len(sv))
360,130✔
336
        if size := uint64(enc.alloc.Size()) + enc.curSize; size > maxEncodedSize {
360,130✔
337
                return fmt.Errorf("estimated response size: %d is bigger than threshold: %d",
×
338
                        size, maxEncodedSize)
×
339
        }
×
340
        return nil
360,130✔
341
}
342

343
func (enc *encoder) setList(fj fastJsonNode, list bool) {
396,358✔
344
        if list {
445,165✔
345
                fj.meta |= listBit
48,807✔
346
        } else {
396,358✔
347
                fj.meta &^= listBit
347,551✔
348
        }
347,551✔
349
}
350

351
func (enc *encoder) setVisited(fj fastJsonNode, visited bool) {
131,052✔
352
        if visited {
262,104✔
353
                fj.meta |= visitedBit
131,052✔
354
        } else {
131,052✔
355
                fj.meta &^= visitedBit
×
356
        }
×
357
}
358

359
func (enc *encoder) setFacetsParent(fj fastJsonNode) {
29✔
360
        fj.meta |= facetsBit
29✔
361
}
29✔
362

363
func (enc *encoder) setCustom(fj fastJsonNode) {
285✔
364
        fj.meta |= customBit
285✔
365
}
285✔
366

367
//nolint:unused // appendAttrs is used in outputnode_test.go as a helper function
368
func (enc *encoder) appendAttrs(fj, child fastJsonNode) {
1✔
369
        enc.addChildren(fj, child)
1✔
370
}
1✔
371

372
// addChildren appends attrs to existing fj's attrs.
373
func (enc *encoder) addChildren(fj, head fastJsonNode) {
408,278✔
374
        if fj.child == nil {
480,397✔
375
                fj.child = head
72,119✔
376
                return
72,119✔
377
        }
72,119✔
378

379
        tail := head
336,159✔
380
        for tail.next != nil {
336,168✔
381
                tail = tail.next
9✔
382
        }
9✔
383

384
        // We're inserting the node in between. This would need to be fixed later via fixOrder.
385
        // Single child additions:
386
        // Child 1
387
        // Child 2 -> 1
388
        // Child 3 -> 2 -> 1
389
        // Child 4 -> 3 -> 2 -> 1
390
        // Child 5 -> 4 -> 3 -> 2 -> 1
391
        //
392
        // If child has siblings, then it could look like this.
393
        // addChildren(13 -> 12 -> 11)
394
        // Child 5 -> 4 -> 3 -> 2 -> 1
395
        //
396
        // What we want:
397
        // 13 -> 12 -> 11 -> 5 -> 4 -> 3 -> 2 -> 1
398
        fj.child, tail.next = head, fj.child
336,159✔
399
}
400

401
// fixOrder would recursively fix the ordering issue caused by addChildren, across the entire
402
// tree.
403
// fixOrder would fix the order from
404
// 5 -> 4 -> 3 -> 2 -> 1 to
405
// 1 -> 2 -> 3 -> 4 -> 5
406
func (enc *encoder) fixOrder(fj fastJsonNode) {
131,053✔
407
        // If you call this again on the same fastJsonNode, then this would become wrong.  Due to
131,053✔
408
        // children being copied over, the same node can be referenced by multiple nodes. Thus, the node
131,053✔
409
        // would be visited again, it would be fixed multiple times, causing ordering issue.
131,053✔
410
        // To avoid this, we keep track of the node by marking it.
131,053✔
411
        if (fj.meta & visitedBit) > 0 {
131,255✔
412
                return
202✔
413
        }
202✔
414
        enc.setVisited(fj, true)
130,851✔
415

130,851✔
416
        tail := fj.child // This is node 5 in the chain mentioned above.
130,851✔
417
        // Edge cases: Child is nil, or only child.
130,851✔
418
        if tail == nil {
192,806✔
419
                return
61,955✔
420
        }
61,955✔
421

422
        if tail.next == nil {
116,882✔
423
                enc.fixOrder(tail)
47,986✔
424
                return
47,986✔
425
        }
47,986✔
426

427
        left, right := tail, tail.next // Left is 5, right is 4.
20,910✔
428
        left.next = nil                // Make left the last child.
20,910✔
429
        for right != nil {
56,067✔
430
                next := right.next        // right of ptr2 (points to 3)
35,157✔
431
                right.next = left         // ptr2 now points left to ptr1 (4 -> 5)
35,157✔
432
                left, right = right, next // Advance both pointers (left = 4, right = 3 and so on)
35,157✔
433
        }
35,157✔
434
        // left is now pointing to 1.
435
        fj.child = left // Child is now pointed to 1.
20,910✔
436

20,910✔
437
        // Now recurse to fix up all children.
20,910✔
438
        child := fj.child
20,910✔
439
        for child != nil {
76,977✔
440
                enc.fixOrder(child)
56,067✔
441
                child = child.next
56,067✔
442
        }
56,067✔
443
}
444

445
func (enc *encoder) getAttr(fj fastJsonNode) uint16 {
168,564✔
446
        return uint16((fj.meta & setBytes76) >> 40)
168,564✔
447
}
168,564✔
448

449
func (enc *encoder) getScalarVal(fj fastJsonNode) ([]byte, error) {
60,508✔
450
        offset := uint32(fj.meta & setBytes4321)
60,508✔
451
        data, err := enc.arena.get(offset)
60,508✔
452
        if err != nil {
60,508✔
453
                return nil, err
×
454
        }
×
455
        if (fj.meta & uidNodeBit) > 0 {
69,585✔
456
                uid := binary.BigEndian.Uint64(data)
9,077✔
457
                return x.ToHex(uid, false), nil
9,077✔
458
        }
9,077✔
459
        return data, nil
51,431✔
460
}
461

462
func (enc *encoder) getList(fj fastJsonNode) bool {
170,573✔
463
        return (fj.meta & listBit) > 0
170,573✔
464
}
170,573✔
465

466
func (enc *encoder) getFacetsParent(fj fastJsonNode) bool {
6,250✔
467
        return (fj.meta & facetsBit) > 0
6,250✔
468
}
6,250✔
469

470
func (enc *encoder) getCustom(fj fastJsonNode) bool {
6,594✔
471
        return (fj.meta & customBit) > 0
6,594✔
472
}
6,594✔
473

474
func (enc *encoder) children(fj fastJsonNode) fastJsonNode {
170,176✔
475
        // Return nil if no attrs are found.
170,176✔
476
        return fj.child
170,176✔
477
}
170,176✔
478

479
func (enc *encoder) AddValue(fj fastJsonNode, attr uint16, v types.Val) error {
303,145✔
480
        return enc.AddListValue(fj, attr, v, false)
303,145✔
481
}
303,145✔
482

483
func (enc *encoder) AddListValue(fj fastJsonNode, attr uint16, v types.Val, list bool) error {
348,914✔
484
        bs, err := valToBytes(v)
348,914✔
485
        if err != nil {
348,916✔
486
                return nil // Ignore this.
2✔
487
        }
2✔
488
        sn, err := enc.makeScalarNode(attr, bs, list)
348,912✔
489
        if err != nil {
348,912✔
490
                return err
×
491
        }
×
492

493
        enc.addChildren(fj, sn)
348,912✔
494
        return nil
348,912✔
495
}
496

497
func (enc *encoder) AddMapChild(fj, val fastJsonNode) {
766✔
498
        var childNode fastJsonNode
766✔
499
        child := enc.children(fj)
766✔
500
        for child != nil {
2,380✔
501
                if enc.getAttr(child) == enc.getAttr(val) {
1,625✔
502
                        childNode = child
11✔
503
                        break
11✔
504
                }
505
                child = child.next
1,603✔
506
        }
507

508
        if childNode == nil {
1,521✔
509
                enc.addChildren(fj, val)
755✔
510
        } else {
766✔
511
                enc.addChildren(childNode, enc.children(val))
11✔
512
        }
11✔
513
}
514

515
func (enc *encoder) AddListChild(fj, child fastJsonNode) {
47,444✔
516
        enc.setList(child, true)
47,444✔
517
        enc.addChildren(fj, child)
47,444✔
518
}
47,444✔
519

520
func (enc *encoder) SetUID(fj fastJsonNode, uid uint64, attr uint16) error {
10,935✔
521
        // if we're in debug mode, uid may be added second time, skip this
10,935✔
522
        if attr == enc.uidAttr {
17,941✔
523
                fjAttrs := enc.children(fj)
7,006✔
524
                for fjAttrs != nil {
7,296✔
525
                        if enc.getAttr(fjAttrs) == attr {
294✔
526
                                return nil
4✔
527
                        }
4✔
528
                        fjAttrs = fjAttrs.next
286✔
529
                }
530
        }
531

532
        un, err := enc.makeUidNode(attr, uid)
10,931✔
533
        if err != nil {
10,931✔
534
                return err
×
535
        }
×
536
        enc.addChildren(fj, un)
10,931✔
537
        return nil
10,931✔
538
}
539

540
func (enc *encoder) IsEmpty(fj fastJsonNode) bool {
63,355✔
541
        return fj.child == nil
63,355✔
542
}
63,355✔
543

544
var (
545
        boolTrue  = []byte("true")
546
        boolFalse = []byte("false")
547

548
        // Below variables are used in stringJsonMarshal function.
549
        bufferPool = sync.Pool{
550
                New: func() interface{} {
4,133✔
551
                        return new(bytes.Buffer)
4,133✔
552
                },
4,133✔
553
        }
554

555
        hex        = "0123456789abcdef"
556
        escapeHTML = true
557
)
558

559
// stringJsonMarshal is replacement for json.Marshal() function only for string type.
560
// This function is encodeState.string(string, escapeHTML) in "encoding/json/encode.go".
561
// It should be in sync with encodeState.string function.
562
func stringJsonMarshal(s string) []byte {
339,233✔
563
        e := bufferPool.Get().(*bytes.Buffer)
339,233✔
564
        e.Reset()
339,233✔
565

339,233✔
566
        e.WriteByte('"')
339,233✔
567
        start := 0
339,233✔
568
        for i := 0; i < len(s); {
618,361✔
569
                if b := s[i]; b < utf8.RuneSelf {
558,152✔
570
                        if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
557,842✔
571
                                i++
278,818✔
572
                                continue
278,818✔
573
                        }
574
                        if start < i {
277✔
575
                                e.WriteString(s[start:i])
71✔
576
                        }
71✔
577
                        e.WriteByte('\\')
206✔
578
                        switch b {
206✔
579
                        case '\\', '"':
8✔
580
                                e.WriteByte(b)
8✔
581
                        case '\n':
70✔
582
                                e.WriteByte('n')
70✔
583
                        case '\r':
×
584
                                e.WriteByte('r')
×
585
                        case '\t':
121✔
586
                                e.WriteByte('t')
121✔
587
                        default:
7✔
588
                                // This encodes bytes < 0x20 except for \t, \n and \r.
7✔
589
                                // If escapeHTML is set, it also escapes <, >, and &
7✔
590
                                // because they can lead to security holes when
7✔
591
                                // user-controlled strings are rendered into JSON
7✔
592
                                // and served to some browsers.
7✔
593
                                e.WriteString(`u00`)
7✔
594
                                e.WriteByte(hex[b>>4])
7✔
595
                                e.WriteByte(hex[b&0xF])
7✔
596
                        }
597
                        i++
206✔
598
                        start = i
206✔
599
                        continue
206✔
600
                }
601
                c, size := utf8.DecodeRuneInString(s[i:])
104✔
602
                if c == utf8.RuneError && size == 1 {
104✔
603
                        if start < i {
×
604
                                e.WriteString(s[start:i])
×
605
                        }
×
606
                        e.WriteString(`\ufffd`)
×
607
                        i += size
×
608
                        start = i
×
609
                        continue
×
610
                }
611
                // U+2028 is LINE SEPARATOR.
612
                // U+2029 is PARAGRAPH SEPARATOR.
613
                // They are both technically valid characters in JSON strings,
614
                // but don't work in JSONP, which has to be evaluated as JavaScript,
615
                // and can lead to security holes there. It is valid JSON to
616
                // escape them, so we do so unconditionally.
617
                // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
618
                if c == '\u2028' || c == '\u2029' {
104✔
619
                        if start < i {
×
620
                                e.WriteString(s[start:i])
×
621
                        }
×
622
                        e.WriteString(`\u202`)
×
623
                        e.WriteByte(hex[c&0xF])
×
624
                        i += size
×
625
                        start = i
×
626
                        continue
×
627
                }
628
                i += size
104✔
629
        }
630
        if start < len(s) {
377,384✔
631
                e.WriteString(s[start:])
38,151✔
632
        }
38,151✔
633
        e.WriteByte('"')
339,233✔
634
        buf := append([]byte(nil), e.Bytes()...)
339,233✔
635
        bufferPool.Put(e)
339,233✔
636
        return buf
339,233✔
637
}
638

639
func valToBytes(v types.Val) ([]byte, error) {
348,949✔
640
        switch v.Tid {
348,949✔
641
        case types.StringID, types.DefaultID:
339,238✔
642
                switch str := v.Value.(type) {
339,238✔
643
                case string:
339,225✔
644
                        return stringJsonMarshal(str), nil
339,225✔
645
                default:
13✔
646
                        return json.Marshal(str)
13✔
647
                }
648
        case types.BinaryID:
×
649
                return []byte(fmt.Sprintf("%q", v.Value)), nil
×
650
        case types.IntID:
7,711✔
651
                // In types.Convert(), we always convert to int64 for IntID type. fmt.Sprintf is slow
7,711✔
652
                // and hence we are using strconv.FormatInt() here. Since int64 and int are most common int
7,711✔
653
                // types we are using FormatInt for those.
7,711✔
654
                switch num := v.Value.(type) {
7,711✔
655
                case int64:
7,710✔
656
                        return []byte(strconv.FormatInt(num, 10)), nil
7,710✔
657
                case int:
1✔
658
                        return []byte(strconv.FormatInt(int64(num), 10)), nil
1✔
659
                default:
×
660
                        return []byte(fmt.Sprintf("%d", v.Value)), nil
×
661
                }
662
        case types.FloatID:
487✔
663
                f, fOk := v.Value.(float64)
487✔
664

487✔
665
                // +Inf, -Inf and NaN are not representable in JSON.
487✔
666
                // Please see https://golang.org/src/encoding/json/encode.go?s=6458:6501#L573
487✔
667
                if !fOk || math.IsInf(f, 0) || math.IsNaN(f) {
489✔
668
                        return nil, errors.New("Unsupported floating point number in float field")
2✔
669
                }
2✔
670

671
                return []byte(fmt.Sprintf("%f", f)), nil
485✔
672
        case types.BoolID:
816✔
673
                if v.Value.(bool) {
1,524✔
674
                        return boolTrue, nil
708✔
675
                }
708✔
676
                return boolFalse, nil
108✔
677
        case types.DateTimeID:
655✔
678
                t := v.Value.(time.Time)
655✔
679
                return marshalTimeJson(t)
655✔
680
        case types.GeoID:
29✔
681
                return geojson.Marshal(v.Value.(geom.T))
29✔
682
        case types.UidID:
13✔
683
                return []byte(fmt.Sprintf("\"%#x\"", v.Value)), nil
13✔
684
        case types.PasswordID:
×
685
                return []byte(fmt.Sprintf("%q", v.Value.(string))), nil
×
686
        default:
×
687
                return nil, errors.New("Unsupported types.Val.Tid")
×
688
        }
689
}
690

691
// marshalTimeJson does what time.MarshalJson does along with supporting RFC3339 non compliant
692
// time zones in a timestamp. While go 1.20 changes the behaviour of time.MarshalJSON, we do
693
// not want to throw error suddenly because we can't marshal the stored data correctly any more.
694
func marshalTimeJson(t time.Time) ([]byte, error) {
670✔
695
        _, offset := t.Zone()
670✔
696
        // normal case
670✔
697
        if types.GoodTimeZone(offset) {
1,330✔
698
                return t.MarshalJSON()
660✔
699
        }
660✔
700

701
        // If zone >23 or <-23, we need to handle this case ourselves.
702
        // This is because, in go1.20, MarshalJSON fails for invalid zones.
703
        // We, for now, call MarshalJSON for timestamp without the zone (or making it UTC zone).
704
        b, err := t.Add(time.Duration(offset) * time.Second).UTC().MarshalJSON()
10✔
705
        if err != nil {
10✔
706
                return nil, err
×
707
        }
×
708

709
        // we will get a byte slice that has Z appended at the end along with a quote (")
710
        // e.g.: []byte("2018-05-28T14:41:57Z"). We replace Z with -/+.
711
        zone := offset / 60
10✔
712
        if zone < 0 {
13✔
713
                b[len(b)-2] = '-'
3✔
714
                zone = -zone
3✔
715
        } else {
10✔
716
                b[len(b)-2] = '+'
7✔
717
        }
7✔
718
        return append(b[:len(b)-1], []byte(fmt.Sprintf("%02d:%02d\"", zone/60, zone%60))...), nil
10✔
719
}
720

721
func (enc *encoder) writeKey(fj fastJsonNode) error {
82,644✔
722
        if _, err := enc.buf.WriteRune('"'); err != nil {
82,644✔
723
                return err
×
724
        }
×
725
        attrID := enc.getAttr(fj)
82,644✔
726
        if _, err := enc.buf.WriteString(enc.attrForID(attrID)); err != nil {
82,644✔
727
                return err
×
728
        }
×
729
        if _, err := enc.buf.WriteRune('"'); err != nil {
82,644✔
730
                return err
×
731
        }
×
732
        if _, err := enc.buf.WriteRune(':'); err != nil {
82,644✔
733
                return err
×
734
        }
×
735
        return nil
82,644✔
736
}
737

738
func (enc *encoder) attachFacets(fj fastJsonNode, fieldName string, isList bool,
739
        fList []*api.Facet, facetIdx int) error {
504✔
740

504✔
741
        idxFieldID := enc.idForAttr(strconv.Itoa(facetIdx))
504✔
742
        for _, f := range fList {
965✔
743
                fName := facetName(fieldName, f)
461✔
744
                fVal, err := facets.ValFor(f)
461✔
745
                if err != nil {
461✔
746
                        return err
×
747
                }
×
748

749
                if !isList {
893✔
750
                        if err := enc.AddValue(fj, enc.idForAttr(fName), fVal); err != nil {
432✔
751
                                return err
×
752
                        }
×
753
                } else {
29✔
754
                        facetNode := enc.newNode(enc.idForAttr(fName))
29✔
755
                        err := enc.AddValue(facetNode, idxFieldID, fVal)
29✔
756
                        if err != nil {
29✔
757
                                return err
×
758
                        }
×
759
                        // Mark this node as facetsParent.
760
                        enc.setFacetsParent(facetNode)
29✔
761
                        enc.AddMapChild(fj, facetNode)
29✔
762
                }
763
        }
764

765
        return nil
504✔
766
}
767

768
func (enc *encoder) encode(fj fastJsonNode) error {
114,675✔
769
        child := enc.children(fj)
114,675✔
770
        // This is a scalar value.
114,675✔
771
        if child == nil {
166,434✔
772
                val, err := enc.getScalarVal(fj)
51,759✔
773
                if err != nil {
51,759✔
774
                        return err
×
775
                }
×
776
                _, err = enc.buf.Write(val)
51,759✔
777
                return err
51,759✔
778
        }
779

780
        // This is an internal node.
781
        if _, err := enc.buf.WriteRune('{'); err != nil {
62,916✔
782
                return err
×
783
        }
×
784
        cnt := 0
62,916✔
785
        var cur, next fastJsonNode
62,916✔
786
        for child != nil {
152,770✔
787
                cnt++
89,854✔
788
                validNext := false
89,854✔
789
                cur = child
89,854✔
790
                if cur.next != nil {
116,792✔
791
                        next = cur.next
26,938✔
792
                        validNext = true
26,938✔
793
                }
26,938✔
794

795
                if validNext && enc.getAttr(cur) == enc.getAttr(next) {
97,064✔
796
                        if cnt == 1 {
10,528✔
797
                                if err := enc.writeKey(cur); err != nil {
3,318✔
798
                                        return err
×
799
                                }
×
800
                                if _, err := enc.buf.WriteRune('['); err != nil {
3,318✔
801
                                        return err
×
802
                                }
×
803
                        }
804
                        if err := enc.encode(cur); err != nil {
7,210✔
805
                                return err
×
806
                        }
×
807
                } else {
82,644✔
808
                        if cnt == 1 {
161,970✔
809
                                if err := enc.writeKey(cur); err != nil {
79,326✔
810
                                        return err
×
811
                                }
×
812
                                if enc.getList(cur) {
110,307✔
813
                                        if _, err := enc.buf.WriteRune('['); err != nil {
30,981✔
814
                                                return err
×
815
                                        }
×
816
                                }
817
                        }
818
                        if err := enc.encode(cur); err != nil {
82,644✔
819
                                return err
×
820
                        }
×
821
                        if cnt > 1 || enc.getList(cur) {
116,943✔
822
                                if _, err := enc.buf.WriteRune(']'); err != nil {
34,299✔
823
                                        return err
×
824
                                }
×
825
                        }
826
                        cnt = 0 // Reset the count.
82,644✔
827
                }
828
                // We need to print comma except for the last attribute.
829
                if child.next != nil {
116,792✔
830
                        if _, err := enc.buf.WriteRune(','); err != nil {
26,938✔
831
                                return err
×
832
                        }
×
833
                }
834

835
                child = child.next
89,854✔
836
        }
837
        if _, err := enc.buf.WriteRune('}'); err != nil {
62,916✔
838
                return err
×
839
        }
×
840

841
        return nil
62,916✔
842
}
843

844
func (enc *encoder) copyFastJsonList(fj fastJsonNode) (fastJsonNode, int) {
234✔
845
        if fj == nil {
236✔
846
                return fj, 0
2✔
847
        }
2✔
848

849
        var head, tail fastJsonNode
232✔
850
        nodeCount := 0
232✔
851

232✔
852
        for fj != nil {
1,671✔
853
                nodeCount++
1,439✔
854
                nn := enc.copySingleNode(fj)
1,439✔
855
                if tail == nil {
1,671✔
856
                        head, tail = nn, nn
232✔
857
                        fj = fj.next
232✔
858
                        continue
232✔
859
                }
860
                tail.next = nn
1,207✔
861
                fj, tail = fj.next, tail.next
1,207✔
862
        }
863

864
        return head, nodeCount
232✔
865
}
866

867
func (enc *encoder) copySingleNode(fj fastJsonNode) fastJsonNode {
2,490✔
868
        if fj == nil {
2,490✔
869
                return nil
×
870
        }
×
871

872
        nn := enc.newNode(enc.getAttr(fj))
2,490✔
873
        nn.meta = fj.meta
2,490✔
874
        nn.child = fj.child
2,490✔
875
        nn.next = nil
2,490✔
876
        return nn
2,490✔
877
}
878

879
func (enc *encoder) merge(parent, child []fastJsonNode) ([]fastJsonNode, error) {
48✔
880
        if len(parent) == 0 {
48✔
881
                return child, nil
×
882
        }
×
883

884
        // Here we merge two slices of maps.
885
        mergedList := make([]fastJsonNode, 0)
48✔
886
        cnt := 0
48✔
887
        for _, pa := range parent {
105✔
888
                for _, ca := range child {
174✔
889
                        paCopy, paNodeCount := enc.copyFastJsonList(pa)
117✔
890
                        caCopy, caNodeCount := enc.copyFastJsonList(ca)
117✔
891

117✔
892
                        cnt += paNodeCount + caNodeCount
117✔
893
                        if cnt > x.Config.LimitNormalizeNode {
118✔
894
                                return nil, errors.Errorf(
1✔
895
                                        "Couldn't evaluate @normalize directive - too many results")
1✔
896
                        }
1✔
897

898
                        if paCopy == nil {
118✔
899
                                paCopy = caCopy
2✔
900
                        } else {
116✔
901
                                temp := paCopy
114✔
902
                                for temp.next != nil {
172✔
903
                                        temp = temp.next
58✔
904
                                }
58✔
905
                                temp.next = caCopy
114✔
906
                        }
907
                        mergedList = append(mergedList, paCopy)
116✔
908
                }
909
        }
910
        return mergedList, nil
47✔
911
}
912

913
// normalize returns all attributes of fj and its children (if any).
914
func (enc *encoder) normalize(fj fastJsonNode) ([]fastJsonNode, error) {
142✔
915
        cnt := 0
142✔
916
        chead := enc.children(fj)
142✔
917
        for chead != nil {
4,417✔
918
                // Here we are counting all non-scalar children of fj. If there are any such
4,275✔
919
                // children, we will flatten them, otherwise we will return all children.
4,275✔
920
                // We should only consider those children(of fj) for flattening which have
4,275✔
921
                // children and are not facetsParent.
4,275✔
922
                if enc.children(chead) != nil && !enc.getFacetsParent(chead) {
7,373✔
923
                        cnt++
3,098✔
924
                }
3,098✔
925
                chead = chead.next
4,275✔
926
        }
927

928
        if cnt == 0 {
239✔
929
                // Recursion base case
97✔
930
                // There are no children, we can just return slice with fj.child.
97✔
931
                return []fastJsonNode{enc.children(fj)}, nil
97✔
932
        }
97✔
933

934
        parentSlice := make([]fastJsonNode, 0, 5)
45✔
935

45✔
936
        // First separate children of fj which are scalar.
45✔
937
        var shead, curScalar fastJsonNode
45✔
938
        chead = enc.children(fj)
45✔
939
        for chead != nil {
4,194✔
940
                if enc.children(chead) != nil && !enc.getFacetsParent(chead) {
7,247✔
941
                        chead = chead.next
3,098✔
942
                        continue
3,098✔
943
                }
944

945
                // Here, add all nodes which have either no children or they are facetsParent.
946
                copyNode := enc.copySingleNode(chead)
1,051✔
947
                if curScalar == nil {
1,094✔
948
                        shead, curScalar = copyNode, copyNode
43✔
949
                } else {
1,051✔
950
                        curScalar.next = copyNode
1,008✔
951
                        curScalar = copyNode
1,008✔
952
                }
1,008✔
953

954
                chead = chead.next
1,051✔
955
        }
956

957
        parentSlice = append(parentSlice, shead)
45✔
958
        chead = enc.children(fj)
45✔
959
        for chead != nil {
144✔
960
                childNode := chead
99✔
961
                // Here, exclude all nodes which have either no children or they are facetsParent.
99✔
962
                if enc.children(childNode) == nil || enc.getFacetsParent(childNode) {
150✔
963
                        chead = chead.next
51✔
964
                        continue
51✔
965
                }
966

967
                childSlice := make([]fastJsonNode, 0, 5)
48✔
968
                for chead != nil && enc.getAttr(childNode) == enc.getAttr(chead) {
147✔
969
                        childSlice = append(childSlice, enc.children(chead))
99✔
970
                        chead = chead.next
99✔
971
                }
99✔
972

973
                var err error
48✔
974
                parentSlice, err = enc.merge(parentSlice, childSlice)
48✔
975
                if err != nil {
49✔
976
                        return nil, err
1✔
977
                }
1✔
978
        }
979

980
        for i, slice := range parentSlice {
148✔
981
                if x.Config.ListInNormalize {
208✔
982
                        // sort the fastJson list. This will ensure that nodes
104✔
983
                        // with same attribute name comes together in response
104✔
984
                        enc.MergeSort(&parentSlice[i])
104✔
985
                }
104✔
986

987
                // From every list we need to remove node with attribute "uid".
988
                var prev, cur fastJsonNode
104✔
989
                cur = slice
104✔
990
                for cur != nil {
274✔
991
                        if enc.getAttr(cur) == enc.uidAttr {
170✔
992
                                if prev == nil {
×
993
                                        cur = cur.next
×
994
                                        continue
×
995
                                } else {
×
996
                                        prev.next = cur.next
×
997
                                }
×
998
                        }
999
                        prev = cur
170✔
1000
                        cur = cur.next
170✔
1001
                }
1002
        }
1003

1004
        return parentSlice, nil
44✔
1005
}
1006

1007
func (sg *SubGraph) addGroupby(enc *encoder, fj fastJsonNode,
1008
        res *groupResults, fname string) error {
36✔
1009

36✔
1010
        // Don't add empty groupby
36✔
1011
        if len(res.group) == 0 {
49✔
1012
                return nil
13✔
1013
        }
13✔
1014
        g := enc.newNode(enc.idForAttr(fname))
23✔
1015
        for _, grp := range res.group {
80✔
1016
                uc := enc.newNode(enc.idForAttr("@groupby"))
57✔
1017
                for _, it := range grp.keys {
130✔
1018
                        if err := enc.AddValue(uc, enc.idForAttr(it.attr), it.key); err != nil {
73✔
1019
                                return err
×
1020
                        }
×
1021
                }
1022
                for _, it := range grp.aggregates {
118✔
1023
                        if err := enc.AddValue(uc, enc.idForAttr(it.attr), it.key); err != nil {
61✔
1024
                                return err
×
1025
                        }
×
1026
                }
1027
                enc.AddListChild(g, uc)
57✔
1028
        }
1029
        enc.AddListChild(fj, g)
23✔
1030
        return nil
23✔
1031
}
1032

1033
func (sg *SubGraph) addAggregations(enc *encoder, fj fastJsonNode) error {
128✔
1034
        for _, child := range sg.Children {
242✔
1035
                aggVal, ok := child.Params.UidToVal[0]
114✔
1036
                if !ok {
128✔
1037
                        if len(child.Params.NeedsVar) == 0 {
15✔
1038
                                return errors.Errorf("Only aggregated variables allowed within empty block.")
1✔
1039
                        }
1✔
1040
                        // the aggregation didn't happen, most likely was called with unset vars.
1041
                        // See: query.go:fillVars
1042
                        // In this case we do nothing. The aggregate value in response will be returned as NULL.
1043
                }
1044
                if child.Params.Normalize && child.Params.Alias == "" {
114✔
1045
                        continue
1✔
1046
                }
1047
                fieldName := child.aggWithVarFieldName()
112✔
1048
                n1 := enc.newNode(enc.idForAttr(sg.Params.Alias))
112✔
1049
                if err := enc.AddValue(n1, enc.idForAttr(fieldName), aggVal); err != nil {
112✔
1050
                        return err
×
1051
                }
×
1052
                enc.AddListChild(fj, n1)
112✔
1053
        }
1054
        if enc.IsEmpty(fj) {
212✔
1055
                enc.AddListChild(fj, enc.newNode(enc.idForAttr(sg.Params.Alias)))
85✔
1056
        }
85✔
1057
        return nil
127✔
1058
}
1059

1060
func (sg *SubGraph) handleCountUIDNodes(enc *encoder, n fastJsonNode, count int) (bool, error) {
37,284✔
1061
        addedNewChild := false
37,284✔
1062
        fieldName := sg.fieldName()
37,284✔
1063
        sgFieldID := enc.idForAttr(fieldName)
37,284✔
1064
        for _, child := range sg.Children {
100,506✔
1065
                uidCount := child.Attr == "uid" && child.Params.DoCount && child.IsInternal()
63,222✔
1066
                normWithoutAlias := child.Params.Alias == "" && child.Params.Normalize
63,222✔
1067
                if uidCount && !normWithoutAlias {
63,309✔
1068
                        addedNewChild = true
87✔
1069

87✔
1070
                        c := types.ValueForType(types.IntID)
87✔
1071
                        c.Value = int64(count)
87✔
1072

87✔
1073
                        field := child.Params.Alias
87✔
1074
                        if field == "" {
160✔
1075
                                field = "count"
73✔
1076
                        }
73✔
1077

1078
                        fjChild := enc.newNode(sgFieldID)
87✔
1079
                        if err := enc.AddValue(fjChild, enc.idForAttr(field), c); err != nil {
87✔
1080
                                return false, err
×
1081
                        }
×
1082
                        enc.AddListChild(n, fjChild)
87✔
1083
                }
1084
        }
1085

1086
        return addedNewChild, nil
37,284✔
1087
}
1088

1089
func processNodeUids(fj fastJsonNode, enc *encoder, sg *SubGraph) error {
28,544✔
1090
        if sg.Params.IsEmpty {
28,672✔
1091
                return sg.addAggregations(enc, fj)
128✔
1092
        }
128✔
1093

1094
        enc.curSize += uint64(len(sg.Params.Alias))
28,416✔
1095

28,416✔
1096
        attrID := enc.idForAttr(sg.Params.Alias)
28,416✔
1097
        if sg.uidMatrix == nil {
28,419✔
1098
                enc.AddListChild(fj, enc.newNode(attrID))
3✔
1099
                return nil
3✔
1100
        }
3✔
1101

1102
        hasChild, err := sg.handleCountUIDNodes(enc, fj, len(sg.DestUIDs.Uids))
28,413✔
1103
        if err != nil {
28,413✔
1104
                return err
×
1105
        }
×
1106
        if sg.Params.IsGroupBy {
28,426✔
1107
                if len(sg.GroupbyRes) == 0 {
13✔
1108
                        return errors.Errorf("Expected GroupbyRes to have length > 0.")
×
1109
                }
×
1110
                return sg.addGroupby(enc, fj, sg.GroupbyRes[0], sg.Params.Alias)
13✔
1111
        }
1112

1113
        lenList := len(sg.uidMatrix[0].Uids)
28,400✔
1114
        for i := 0; i < lenList; i++ {
80,195✔
1115
                uid := sg.uidMatrix[0].Uids[i]
51,795✔
1116
                if algo.IndexOf(sg.DestUIDs, uid) < 0 {
51,863✔
1117
                        // This UID was filtered. So Ignore it.
68✔
1118
                        continue
68✔
1119
                }
1120

1121
                n1 := enc.newNode(attrID)
51,727✔
1122
                enc.setAttr(n1, enc.idForAttr(sg.Params.Alias))
51,727✔
1123
                if err := sg.preTraverse(enc, uid, n1); err != nil {
51,728✔
1124
                        if err.Error() == "_INV_" {
1✔
1125
                                continue
×
1126
                        }
1127
                        return err
1✔
1128
                }
1129

1130
                if enc.IsEmpty(n1) {
72,644✔
1131
                        continue
20,918✔
1132
                }
1133

1134
                hasChild = true
30,808✔
1135
                if !sg.Params.Normalize {
61,599✔
1136
                        enc.AddListChild(fj, n1)
30,791✔
1137
                        continue
30,791✔
1138
                }
1139

1140
                // With the new changes we store children in reverse order(check addChildren method). This
1141
                // leads to change of order of field responses for existing Normalize test cases. To
1142
                // minimize the changes of existing tests case we are fixing order of node children before
1143
                // calling normalize() on it. Also once we have fixed order for children, we don't need to
1144
                // fix its order again. Hence mark the newly created node visited immediately.
1145
                enc.fixOrder(n1)
17✔
1146
                // Lets normalize the response now.
17✔
1147
                normalized, err := enc.normalize(n1)
17✔
1148
                if err != nil {
17✔
1149
                        return err
×
1150
                }
×
1151
                for _, c := range normalized {
71✔
1152
                        node := enc.newNode(attrID)
54✔
1153
                        enc.setVisited(node, true)
54✔
1154
                        enc.addChildren(node, c)
54✔
1155
                        enc.AddListChild(fj, node)
54✔
1156
                }
54✔
1157
        }
1158

1159
        if !hasChild {
31,338✔
1160
                // So that we return an empty key if the root didn't have any children.
2,939✔
1161
                enc.AddListChild(fj, enc.newNode(attrID))
2,939✔
1162
        }
2,939✔
1163
        return nil
28,399✔
1164
}
1165

1166
// Extensions represents the extra information appended to query results.
1167
type Extensions struct {
1168
        Latency *api.Latency    `json:"server_latency,omitempty"`
1169
        Txn     *api.TxnContext `json:"txn,omitempty"`
1170
        Metrics *api.Metrics    `json:"metrics,omitempty"`
1171
}
1172

1173
func (sg *SubGraph) toFastJSON(ctx context.Context, l *Latency, field gqlSchema.Field) ([]byte,
1174
        error) {
26,859✔
1175
        encodingStart := time.Now()
26,859✔
1176
        defer func() {
53,718✔
1177
                l.Json = time.Since(encodingStart)
26,859✔
1178
        }()
26,859✔
1179

1180
        enc := newEncoder()
26,859✔
1181
        defer func() {
53,718✔
1182
                // Put encoder's arena back to arena pool.
26,859✔
1183
                arenaPool.Put(enc.arena)
26,859✔
1184
                enc.alloc.Release()
26,859✔
1185
        }()
26,859✔
1186

1187
        var err error
26,859✔
1188
        n := enc.newNode(enc.idForAttr("_root_"))
26,859✔
1189
        for _, sg := range sg.Children {
55,403✔
1190
                err = processNodeUids(n, enc, sg)
28,544✔
1191
                if err != nil {
28,546✔
1192
                        return nil, err
2✔
1193
                }
2✔
1194
        }
1195
        enc.fixOrder(n)
26,857✔
1196

26,857✔
1197
        // According to GraphQL spec response should only contain data, errors and extensions as top
26,857✔
1198
        // level keys. Hence we send server_latency under extensions key.
26,857✔
1199
        // https://facebook.github.io/graphql/#sec-Response-Format
26,857✔
1200

26,857✔
1201
        // if there is a GraphQL field that means we need to encode the response in GraphQL form,
26,857✔
1202
        // otherwise encode it in DQL form.
26,857✔
1203
        if field != nil {
28,825✔
1204
                // if there were any GraphQL errors, we need to propagate them back to GraphQL layer along
1,968✔
1205
                // with the data. So, don't return here if we get an error.
1,968✔
1206
                err = sg.toGraphqlJSON(newGraphQLEncoder(ctx, enc), n, field)
1,968✔
1207
        } else if err = sg.toDqlJSON(enc, n); err != nil {
26,857✔
1208
                return nil, err
×
1209
        }
×
1210

1211
        // Return error if encoded buffer size exceeds than a threshold size.
1212
        if uint64(enc.buf.Len()) > maxEncodedSize {
26,857✔
1213
                return nil, fmt.Errorf("while writing to buffer. Encoded response size: %d"+
×
1214
                        " is bigger than threshold: %d", enc.buf.Len(), maxEncodedSize)
×
1215
        }
×
1216

1217
        return enc.buf.Bytes(), err
26,857✔
1218
}
1219

1220
func (sg *SubGraph) toDqlJSON(enc *encoder, n fastJsonNode) error {
24,889✔
1221
        if enc.children(n) == nil {
24,960✔
1222
                x.Check2(enc.buf.WriteString(`{}`))
71✔
1223
                return nil
71✔
1224
        }
71✔
1225
        return enc.encode(n)
24,818✔
1226
}
1227

1228
func (sg *SubGraph) toGraphqlJSON(genc *graphQLEncoder, n fastJsonNode, f gqlSchema.Field) error {
1,968✔
1229
        // GraphQL queries will always have at least one query whose results are visible to users,
1,968✔
1230
        // implying that the root fastJson node will always have at least one child. So, no need
1,968✔
1231
        // to check for the case where there are no children for the root fastJson node.
1,968✔
1232

1,968✔
1233
        // if this field has any @custom(http: {...}) children,
1,968✔
1234
        // then need to resolve them first before encoding the final GraphQL result.
1,968✔
1235
        genc.processCustomFields(f, n)
1,968✔
1236
        // now encode the GraphQL results.
1,968✔
1237
        if !genc.encode(encodeInput{
1,968✔
1238
                parentField: nil,
1,968✔
1239
                parentPath:  f.PreAllocatePathSlice(),
1,968✔
1240
                fj:          n,
1,968✔
1241
                fjIsRoot:    true,
1,968✔
1242
                childSelSet: []gqlSchema.Field{f},
1,968✔
1243
        }) {
1,968✔
1244
                // if genc.encode() didn't finish successfully here, that means we need to send
×
1245
                // data as null in the GraphQL response like this:
×
1246
                //                 {
×
1247
                //                         "errors": [...],
×
1248
                //                         "data": null
×
1249
                //                 }
×
1250
                // and not just null for a single query in data.
×
1251
                // So, reset the buffer contents here, so that GraphQL layer may know that if it gets
×
1252
                // error of type x.GqlErrorList along with nil JSON response, then it needs to set whole
×
1253
                // data as null.
×
1254
                genc.buf.Reset()
×
1255
        }
×
1256

1257
        if len(genc.errs) > 0 {
1,979✔
1258
                return genc.errs
11✔
1259
        }
11✔
1260
        return nil
1,957✔
1261
}
1262

1263
func (sg *SubGraph) fieldName() string {
115,608✔
1264
        fieldName := sg.Attr
115,608✔
1265
        if sg.Params.Alias != "" {
159,903✔
1266
                fieldName = sg.Params.Alias
44,295✔
1267
        }
44,295✔
1268
        return fieldName
115,608✔
1269
}
1270

1271
func (sg *SubGraph) addCount(enc *encoder, count uint64, dst fastJsonNode) error {
102✔
1272
        if sg.Params.Normalize && sg.Params.Alias == "" {
103✔
1273
                return nil
1✔
1274
        }
1✔
1275
        c := types.ValueForType(types.IntID)
101✔
1276
        c.Value = int64(count)
101✔
1277
        fieldName := sg.Params.Alias
101✔
1278
        if fieldName == "" {
153✔
1279
                fieldName = fmt.Sprintf("count(%s)", sg.Attr)
52✔
1280
        }
52✔
1281
        return enc.AddValue(dst, enc.idForAttr(fieldName), c)
101✔
1282
}
1283

1284
func (sg *SubGraph) aggWithVarFieldName() string {
821✔
1285
        if sg.Params.Alias != "" {
1,338✔
1286
                return sg.Params.Alias
517✔
1287
        }
517✔
1288
        fieldName := fmt.Sprintf("val(%v)", sg.Params.Var)
304✔
1289
        if len(sg.Params.NeedsVar) > 0 {
571✔
1290
                fieldName = fmt.Sprintf("val(%v)", sg.Params.NeedsVar[0].Name)
267✔
1291
                if sg.SrcFunc != nil {
308✔
1292
                        fieldName = fmt.Sprintf("%s(%v)", sg.SrcFunc.Name, fieldName)
41✔
1293
                }
41✔
1294
        }
1295
        return fieldName
304✔
1296
}
1297

1298
func (sg *SubGraph) addInternalNode(enc *encoder, uid uint64, dst fastJsonNode) error {
21,417✔
1299
        sv, ok := sg.Params.UidToVal[uid]
21,417✔
1300
        if !ok || sv.Value == nil {
42,125✔
1301
                return nil
20,708✔
1302
        }
20,708✔
1303
        fieldName := sg.aggWithVarFieldName()
709✔
1304
        return enc.AddValue(dst, enc.idForAttr(fieldName), sv)
709✔
1305
}
1306

1307
func (sg *SubGraph) addCheckPwd(enc *encoder, vals []*pb.TaskValue, dst fastJsonNode) error {
469✔
1308
        c := types.ValueForType(types.BoolID)
469✔
1309
        if len(vals) == 0 {
470✔
1310
                c.Value = false
1✔
1311
        } else {
469✔
1312
                c.Value = task.ToBool(vals[0])
468✔
1313
        }
468✔
1314

1315
        fieldName := sg.Params.Alias
469✔
1316
        if fieldName == "" {
489✔
1317
                fieldName = fmt.Sprintf("checkpwd(%s)", sg.Attr)
20✔
1318
        }
20✔
1319
        return enc.AddValue(dst, enc.idForAttr(fieldName), c)
469✔
1320
}
1321

1322
func alreadySeen(parentIds []uint64, uid uint64) bool {
48✔
1323
        for _, id := range parentIds {
102✔
1324
                if id == uid {
60✔
1325
                        return true
6✔
1326
                }
6✔
1327
        }
1328
        return false
42✔
1329
}
1330

1331
func facetName(fieldName string, f *api.Facet) string {
461✔
1332
        if f.Alias != "" {
466✔
1333
                return f.Alias
5✔
1334
        }
5✔
1335
        return fieldName + x.FacetDelimiter + f.Key
456✔
1336
}
1337

1338
// This method gets the values and children for a subprotos.
1339
func (sg *SubGraph) preTraverse(enc *encoder, uid uint64, dst fastJsonNode) error {
63,170✔
1340
        if sg.Params.IgnoreReflex {
63,218✔
1341
                if alreadySeen(sg.Params.ParentIds, uid) {
54✔
1342
                        // A node can't have itself as the child at any level.
6✔
1343
                        return nil
6✔
1344
                }
6✔
1345
                // Push myself to stack before sending this to children.
1346
                sg.Params.ParentIds = append(sg.Params.ParentIds, uid)
42✔
1347
        }
1348

1349
        var invalidUids map[uint64]bool
63,164✔
1350
        // We go through all predicate children of the subprotos.
63,164✔
1351
        for _, pc := range sg.Children {
162,958✔
1352
                if pc.Params.IgnoreResult {
99,794✔
1353
                        continue
×
1354
                }
1355
                if pc.IsInternal() {
121,215✔
1356
                        if pc.Params.Expand != "" {
21,421✔
1357
                                continue
×
1358
                        }
1359
                        if pc.Params.Normalize && pc.Params.Alias == "" {
21,425✔
1360
                                continue
4✔
1361
                        }
1362
                        if err := pc.addInternalNode(enc, uid, dst); err != nil {
21,417✔
1363
                                return err
×
1364
                        }
×
1365
                        continue
21,417✔
1366
                }
1367

1368
                if len(pc.uidMatrix) == 0 {
78,476✔
1369
                        // Can happen in recurse query.
103✔
1370
                        continue
103✔
1371
                }
1372
                if len(pc.facetsMatrix) > 0 && len(pc.facetsMatrix) != len(pc.uidMatrix) {
78,270✔
1373
                        return errors.Errorf("Length of facetsMatrix and uidMatrix mismatch: %d vs %d",
×
1374
                                len(pc.facetsMatrix), len(pc.uidMatrix))
×
1375
                }
×
1376

1377
                idx := algo.IndexOf(pc.SrcUIDs, uid)
78,270✔
1378
                if idx < 0 {
78,270✔
1379
                        continue
×
1380
                }
1381
                if pc.Params.IsGroupBy {
78,293✔
1382
                        if len(pc.GroupbyRes) <= idx {
23✔
1383
                                return errors.Errorf("Unexpected length while adding Groupby. Idx: [%v], len: [%v]",
×
1384
                                        idx, len(pc.GroupbyRes))
×
1385
                        }
×
1386
                        if err := pc.addGroupby(enc, dst, pc.GroupbyRes[idx], pc.fieldName()); err != nil {
23✔
1387
                                return err
×
1388
                        }
×
1389
                        continue
23✔
1390
                }
1391

1392
                fieldName := pc.fieldName()
78,247✔
1393
                switch {
78,247✔
1394
                case len(pc.counts) > 0:
102✔
1395
                        if err := pc.addCount(enc, uint64(pc.counts[idx]), dst); err != nil {
102✔
1396
                                return err
×
1397
                        }
×
1398

1399
                case pc.SrcFunc != nil && pc.SrcFunc.Name == "checkpwd":
469✔
1400
                        if err := pc.addCheckPwd(enc, pc.valueMatrix[idx].Values, dst); err != nil {
469✔
1401
                                return err
×
1402
                        }
×
1403

1404
                case idx < len(pc.uidMatrix) && len(pc.uidMatrix[idx].Uids) > 0:
8,871✔
1405
                        var fcsList []*pb.Facets
8,871✔
1406
                        if pc.Params.Facet != nil {
9,136✔
1407
                                fcsList = pc.facetsMatrix[idx].FacetsList
265✔
1408
                        }
265✔
1409

1410
                        if sg.Params.IgnoreReflex {
8,886✔
1411
                                pc.Params.ParentIds = sg.Params.ParentIds
15✔
1412
                        }
15✔
1413

1414
                        // calculate it once to avoid multiple call to idToAttr()
1415
                        fieldID := enc.idForAttr(fieldName)
8,871✔
1416
                        // Add len of fieldName to enc.curSize.
8,871✔
1417
                        enc.curSize += uint64(len(fieldName))
8,871✔
1418

8,871✔
1419
                        // We create as many predicate entity children as the length of uids for
8,871✔
1420
                        // this predicate.
8,871✔
1421
                        ul := pc.uidMatrix[idx]
8,871✔
1422
                        for childIdx, childUID := range ul.Uids {
20,380✔
1423
                                if fieldName == "" || (invalidUids != nil && invalidUids[childUID]) {
11,575✔
1424
                                        continue
66✔
1425
                                }
1426
                                uc := enc.newNode(fieldID)
11,443✔
1427
                                if rerr := pc.preTraverse(enc, childUID, uc); rerr != nil {
11,443✔
1428
                                        if rerr.Error() == "_INV_" {
×
1429
                                                if invalidUids == nil {
×
1430
                                                        invalidUids = make(map[uint64]bool)
×
1431
                                                }
×
1432

1433
                                                invalidUids[childUID] = true
×
1434
                                                continue // next UID.
×
1435
                                        }
1436
                                        return rerr
×
1437
                                }
1438

1439
                                if !enc.IsEmpty(uc) {
22,447✔
1440
                                        if sg.Params.GetUid {
11,008✔
1441
                                                if err := enc.SetUID(uc, childUID, enc.uidAttr); err != nil {
4✔
1442
                                                        return err
×
1443
                                                }
×
1444
                                        }
1445

1446
                                        // Add facets nodes.
1447
                                        if pc.Params.Facet != nil && len(fcsList) > childIdx {
11,347✔
1448
                                                fs := fcsList[childIdx].Facets
343✔
1449
                                                if err := enc.attachFacets(uc, fieldName, false, fs, childIdx); err != nil {
343✔
1450
                                                        return err
×
1451
                                                }
×
1452
                                        }
1453

1454
                                        if pc.Params.Normalize {
11,128✔
1455
                                                // We will normalize at each level instead of
124✔
1456
                                                // calling normalize after pretraverse.
124✔
1457
                                                // Now normalize() only flattens one level,
124✔
1458
                                                // the expectation is that its children have
124✔
1459
                                                // already been normalized.
124✔
1460

124✔
1461
                                                // TODO(ashish): Check reason for calling fixOrder() here in
124✔
1462
                                                // processNodeUids(), just before calling normalize().
124✔
1463
                                                enc.fixOrder(uc)
124✔
1464
                                                normAttrs, err := enc.normalize(uc)
124✔
1465
                                                if err != nil {
124✔
1466
                                                        return err
×
1467
                                                }
×
1468

1469
                                                for _, c := range normAttrs {
271✔
1470
                                                        // Adding as list child irrespective of the type of pc
147✔
1471
                                                        // (list or non-list), otherwise result might be inconsistent or might
147✔
1472
                                                        // depend on children and grandchildren of pc. Consider the case:
147✔
1473
                                                        //         boss: uid .
147✔
1474
                                                        //         friend: [uid] .
147✔
1475
                                                        //         name: string .
147✔
1476
                                                        // For query like:
147✔
1477
                                                        // {
147✔
1478
                                                        //         me(func: uid(0x1)) {
147✔
1479
                                                        //                 boss @normalize {
147✔
1480
                                                        //                         name
147✔
1481
                                                        //                 }
147✔
1482
                                                        //         }
147✔
1483
                                                        // }
147✔
1484
                                                        // boss will be non list type in response, but for query like:
147✔
1485
                                                        // {
147✔
1486
                                                        //         me(func: uid(0x1)) {
147✔
1487
                                                        //                 boss @normalize {
147✔
1488
                                                        //                         friend {
147✔
1489
                                                        //                                 name
147✔
1490
                                                        //                         }
147✔
1491
                                                        //                 }
147✔
1492
                                                        //         }
147✔
1493
                                                        // }
147✔
1494
                                                        // boss should be of list type because there can be multiple friends of
147✔
1495
                                                        // boss.
147✔
1496
                                                        node := enc.newNode(fieldID)
147✔
1497
                                                        enc.setVisited(node, true)
147✔
1498
                                                        enc.addChildren(node, c)
147✔
1499
                                                        enc.AddListChild(dst, node)
147✔
1500
                                                }
147✔
1501
                                                continue
124✔
1502
                                        }
1503
                                        if pc.List {
21,023✔
1504
                                                enc.AddListChild(dst, uc)
10,143✔
1505
                                        } else {
10,880✔
1506
                                                enc.AddMapChild(dst, uc)
737✔
1507
                                        }
737✔
1508
                                }
1509
                        }
1510

1511
                        // add value for count(uid) nodes if any.
1512
                        if _, err := pc.handleCountUIDNodes(enc, dst, len(ul.Uids)); err != nil {
8,871✔
1513
                                return err
×
1514
                        }
×
1515
                default:
68,805✔
1516
                        if pc.Params.Alias == "" && len(pc.Params.Langs) > 0 && pc.Params.Langs[0] != "*" {
69,309✔
1517
                                fieldName += "@"
504✔
1518
                                fieldName += strings.Join(pc.Params.Langs, ":")
504✔
1519
                        }
504✔
1520

1521
                        // calculate it once to avoid multiple call to idToAttr()
1522
                        fieldID := enc.idForAttr(fieldName)
68,805✔
1523
                        // Add len of fieldName to enc.curSize.
68,805✔
1524
                        enc.curSize += uint64(len(fieldName))
68,805✔
1525

68,805✔
1526
                        if pc.Attr == "uid" {
79,433✔
1527
                                if err := enc.SetUID(dst, uid, fieldID); err != nil {
10,628✔
1528
                                        return err
×
1529
                                }
×
1530
                                continue
10,628✔
1531
                        }
1532

1533
                        if len(pc.facetsMatrix) > idx && len(pc.facetsMatrix[idx].FacetsList) > 0 {
58,326✔
1534
                                // In case of Value we have only one Facets.
149✔
1535
                                for i, fcts := range pc.facetsMatrix[idx].FacetsList {
310✔
1536
                                        if err := enc.attachFacets(dst, fieldName, pc.List, fcts.Facets, i); err != nil {
161✔
1537
                                                return err
×
1538
                                        }
×
1539
                                }
1540
                        }
1541

1542
                        if len(pc.valueMatrix) <= idx {
69,531✔
1543
                                continue
11,354✔
1544
                        }
1545

1546
                        for i, tv := range pc.valueMatrix[idx].Values {
92,624✔
1547
                                // if conversion not possible, we ignore it in the result.
45,801✔
1548
                                sv, convErr := convertWithBestEffort(tv, pc.Attr)
45,801✔
1549
                                if convErr != nil {
45,802✔
1550
                                        return convErr
1✔
1551
                                }
1✔
1552

1553
                                if pc.Params.ExpandAll && len(pc.LangTags[idx].Lang) != 0 {
45,890✔
1554
                                        if i >= len(pc.LangTags[idx].Lang) {
90✔
1555
                                                return errors.Errorf(
×
1556
                                                        "pb.error: all lang tags should be either present or absent")
×
1557
                                        }
×
1558
                                        fieldNameWithTag := fieldName
90✔
1559
                                        lang := pc.LangTags[idx].Lang[i]
90✔
1560
                                        if lang != "" && lang != "*" {
100✔
1561
                                                fieldNameWithTag += "@" + lang
10✔
1562
                                        }
10✔
1563
                                        encodeAsList := pc.List && lang == ""
90✔
1564
                                        if err := enc.AddListValue(dst, enc.idForAttr(fieldNameWithTag),
90✔
1565
                                                sv, encodeAsList); err != nil {
90✔
1566
                                                return err
×
1567
                                        }
×
1568
                                        continue
90✔
1569
                                }
1570

1571
                                encodeAsList := pc.List && len(pc.Params.Langs) == 0
45,710✔
1572
                                if !pc.Params.Normalize {
91,239✔
1573
                                        err := enc.AddListValue(dst, fieldID, sv, encodeAsList)
45,529✔
1574
                                        if err != nil {
45,529✔
1575
                                                return err
×
1576
                                        }
×
1577
                                        continue
45,529✔
1578
                                }
1579
                                // If the query had the normalize directive, then we only add nodes
1580
                                // with an Alias.
1581
                                if pc.Params.Alias != "" {
331✔
1582
                                        err := enc.AddListValue(dst, fieldID, sv, encodeAsList)
150✔
1583
                                        if err != nil {
150✔
1584
                                                return err
×
1585
                                        }
×
1586
                                }
1587
                        }
1588
                }
1589
        }
1590

1591
        if sg.Params.IgnoreReflex && len(sg.Params.ParentIds) > 0 {
63,205✔
1592
                // Lets pop the stack.
42✔
1593
                sg.Params.ParentIds = (sg.Params.ParentIds)[:len(sg.Params.ParentIds)-1]
42✔
1594
        }
42✔
1595

1596
        // Only for shortest path query we want to return uid always if there is
1597
        // nothing else at that level.
1598
        if (sg.Params.GetUid && !enc.IsEmpty(dst)) || sg.Params.Shortest {
63,466✔
1599
                if err := enc.SetUID(dst, uid, enc.uidAttr); err != nil {
303✔
1600
                        return err
×
1601
                }
×
1602
        }
1603

1604
        if sg.pathMeta != nil {
63,229✔
1605
                totalWeight := types.Val{
66✔
1606
                        Tid:   types.FloatID,
66✔
1607
                        Value: sg.pathMeta.weight,
66✔
1608
                }
66✔
1609
                if err := enc.AddValue(dst, enc.idForAttr("_weight_"), totalWeight); err != nil {
66✔
1610
                        return err
×
1611
                }
×
1612
        }
1613

1614
        return nil
63,163✔
1615
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc