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

stephenafamo / bob / 17002678275

16 Aug 2025 01:28AM UTC coverage: 41.658% (+0.06%) from 41.598%
17002678275

push

github

stephenafamo
Properly detect end of function in postgres query parser

0 of 1 new or added line in 1 file covered. (0.0%)

110 existing lines in 2 files now uncovered.

9556 of 22939 relevant lines covered (41.66%)

567.51 hits per line

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

66.17
/gen/bobgen-psql/driver/parser/walker.go
1
package parser
2

3
import (
4
        "fmt"
5
        "io"
6
        "reflect"
7
        "sort"
8
        "strconv"
9
        "strings"
10
        "sync/atomic"
11

12
        pg "github.com/pganalyze/pg_query_go/v6"
13
        "github.com/stephenafamo/bob/internal"
14
)
15

16
const (
17
        openParToken  = pg.Token_ASCII_40
18
        closeParToken = pg.Token_ASCII_41
19
)
20

21
func newNodeInfo() nodeInfo {
2,608✔
22
        return nodeInfo{
2,608✔
23
                start:    -1,
2,608✔
24
                end:      -1,
2,608✔
25
                children: make(map[string]nodeInfo),
2,608✔
26
        }
2,608✔
27
}
2,608✔
28

29
type nodeInfo struct {
30
        start, end int32
31
        children   map[string]nodeInfo
32
}
33

34
func (n nodeInfo) isValid() bool {
900✔
35
        return n.start >= 0 && n.end >= 0
900✔
36
}
900✔
37

38
func (info nodeInfo) addChild(name string, childInfo nodeInfo) nodeInfo {
780✔
39
        if !childInfo.isValid() {
860✔
40
                return info
80✔
41
        }
80✔
42
        if childInfo.start != -1 && (info.start == -1 || childInfo.start < info.start) {
1,212✔
43
                info.start = childInfo.start
512✔
44
        }
512✔
45
        if childInfo.end != -1 && (info.end == -1 || childInfo.end > info.end) {
1,336✔
46
                info.end = childInfo.end
636✔
47
        }
636✔
48
        info.children[name] = childInfo
700✔
49

700✔
50
        return info
700✔
51
}
52

53
func (n nodeInfo) String() string {
×
54
        return fmt.Sprintf("%d:%d -> (%d)", n.start, n.end, len(n.children))
×
55
}
×
56

57
func (n nodeInfo) position() position {
640✔
58
        return position{n.start, n.end}
640✔
59
}
640✔
60

61
type col struct {
62
        pos      position
63
        name     string
64
        nullable bool
65
}
66

67
func (c col) LitterDump(w io.Writer) {
×
68
        fmt.Fprintf(w, "(%s, %s, %t)", c.name, c.pos.String(), c.nullable)
×
69
}
×
70

71
type queryResult struct {
72
        schema          string
73
        name            string
74
        columns         []col
75
        mustBeQualified bool
76
}
77

78
type walker struct {
79
        db           tables
80
        sharedSchema string
81
        names        map[position]string
82
        nullability  map[position]nullable
83
        groups       map[argPos]struct{}
84
        multiple     map[[2]int]struct{}
85

86
        position int32
87
        input    string
88
        tokens   []*pg.ScanToken
89

90
        editRules []internal.EditRule
91
        imports   [][]string
92
        mods      *strings.Builder
93

94
        atom *atomic.Int64
95
        args [][]argPos
96

97
        errors []error
98
}
99

100
func (w *walker) matchNames(p1 [2]int32, p2 [2]int32) {
20✔
101
        w.maybeSetName(p1, w.names[p2])
20✔
102
        w.maybeSetName(p2, w.names[p1])
20✔
103
}
20✔
104

105
func (w *walker) maybeSetName(p [2]int32, name string) {
288✔
106
        _, ok := w.names[p]
288✔
107
        if ok {
400✔
108
                return
112✔
109
        }
112✔
110

111
        if len(name) >= 2 {
332✔
112
                switch {
156✔
113
                case name[0] == '"' && name[len(name)-1] == '"':
×
114
                        name = name[1 : len(name)-1]
×
115
                case name[0] == '\'' && name[len(name)-1] == '\'':
×
116
                        name = name[1 : len(name)-1]
×
117
                }
118
        }
119

120
        if name == "" {
176✔
121
                return
×
122
        }
×
123

124
        w.names[p] = name
176✔
125
}
126

127
func (w *walker) setNull(p [2]int32, n nullable) {
100✔
128
        if n == nil {
128✔
129
                return
28✔
130
        }
28✔
131

132
        if prev, ok := w.nullability[p]; ok {
92✔
133
                w.nullability[p] = makeAnyNullable(n, prev)
20✔
134
                return
20✔
135
        }
20✔
136

137
        w.nullability[p] = n
52✔
138
}
139

140
func (w *walker) setGroup(pos argPos) {
36✔
141
        w.groups[pos] = struct{}{}
36✔
142
}
36✔
143

144
func (w *walker) setMultiple(pos [2]int) {
16✔
145
        w.multiple[pos] = struct{}{}
16✔
146
}
16✔
147

148
func (w *walker) updatePosition(pos int32) {
1,588✔
149
        if pos <= 0 {
2,244✔
150
                return
656✔
151
        }
656✔
152
        w.position = pos
932✔
153
}
154

155
func (w *walker) walk(a any) nodeInfo {
1,352✔
156
        if a == nil {
1,352✔
157
                return newNodeInfo()
×
158
        }
×
159

160
        info := newNodeInfo()
1,352✔
161

1,352✔
162
        switch a := a.(type) {
1,352✔
163
        case *pg.Node:
392✔
164
                if a != nil {
692✔
165
                        info = w.reflectWalk(reflect.ValueOf(a.Node))
300✔
166
                }
300✔
167

168
        case *pg.NullTest:
×
169
                info = w.walkNullTest(a)
×
170

171
        case *pg.A_Const:
×
172
                info = w.walkAConst(a)
×
173

174
        case *pg.A_Star:
12✔
175
                info = w.findTokenAfter(w.position, pg.Token_ASCII_42)
12✔
176
                if info.isValid() {
24✔
177
                        w.maybeSetName(info.position(), w.input[info.start:info.end])
12✔
178
                }
12✔
179

180
        case *pg.CoalesceExpr:
×
181
                info = w.reflectWalk(reflect.ValueOf(a))
×
182
                for _, argInfo := range info.children["Args"].children {
×
183
                        w.setNull(argInfo.position(), alwaysNullable{})
×
184
                }
×
185

186
        case *pg.SelectStmt:
60✔
187
                info = w.walkSelectStmt(a)
60✔
188

189
        case *pg.InsertStmt:
12✔
190
                info = w.walkInsertStmt(a)
12✔
191

192
        case *pg.UpdateStmt:
4✔
193
                info = w.walkUpdateStmt(a)
4✔
194

195
        case *pg.DeleteStmt:
4✔
196
                info = w.walkDeleteStmt(a)
4✔
197

198
        case *pg.ParamRef:
48✔
199
                info = w.walkParamRef(a)
48✔
200

201
        case *pg.A_Expr:
20✔
202
                info = w.walkAExpr(a)
20✔
203

204
        case *pg.ColumnRef:
40✔
205
                info = w.walkColumnRef(a)
40✔
206

207
        case *pg.ResTarget:
48✔
208
                info = w.walkResTarget(a)
48✔
209

210
        case *pg.RangeVar:
32✔
211
                info = w.walkRangeVar(a)
32✔
212

213
        case *pg.Alias:
32✔
214
                info = w.walkAlias(a)
32✔
215

216
        case *pg.String:
56✔
217
                info = w.walkString(a)
56✔
218

219
        case *pg.SortBy:
×
220
                info = w.walkSortBy(a)
×
221

222
        case *pg.FuncCall:
×
223
                info = w.walkFuncCall(a)
×
224

225
        case *pg.List:
24✔
226
                info = w.walkList(a)
24✔
227

228
        case *pg.RowExpr:
×
229
                info = w.walkRowExpr(a)
×
230

231
        case *pg.A_ArrayExpr:
×
232
                info = w.walkAArrayExpr(a)
×
233

234
        case *pg.OnConflictClause:
12✔
235
                info = w.walkOnConflictClause(a)
12✔
236

237
        case reflect.Value:
×
238
                info = w.reflectWalk(a)
×
239

240
        default:
556✔
241
                info = w.reflectWalk(reflect.ValueOf(a))
556✔
242
        }
243

244
        w.updatePosition(info.end)
1,352✔
245

1,352✔
246
        return info
1,352✔
247
}
248

249
func (w *walker) reflectWalk(reflected reflect.Value) nodeInfo {
1,040✔
250
        if !reflected.IsValid() {
1,040✔
251
                return newNodeInfo()
×
252
        }
×
253

254
        if reflected.Kind() == reflect.Slice {
1,376✔
255
                info := newNodeInfo()
336✔
256
                for i := range reflected.Len() {
512✔
257
                        childInfo := w.walk(reflected.Index(i).Interface())
176✔
258
                        info = info.addChild(strconv.Itoa(i), childInfo)
176✔
259
                }
176✔
260
                return info
336✔
261
        }
262

263
        refStruct := reflected
704✔
264

704✔
265
        if reflected.Kind() == reflect.Ptr {
1,248✔
266
                if reflected.IsNil() {
616✔
267
                        return newNodeInfo()
72✔
268
                }
72✔
269
                refStruct = reflected.Elem()
472✔
270
        }
271

272
        if refStruct.Kind() != reflect.Struct {
792✔
273
                return newNodeInfo()
160✔
274
        }
160✔
275

276
        info := newNodeInfo()
472✔
277

472✔
278
        LocationField := refStruct.FieldByName("Location")
472✔
279
        if LocationField.IsValid() && LocationField.Kind() == reflect.Int32 {
580✔
280
                info.start = int32(LocationField.Int())
108✔
281
                w.updatePosition(info.start)
108✔
282
                info.end = w.getEnd(info.start)
108✔
283
        }
108✔
284

285
        for i := range refStruct.NumField() {
2,212✔
286
                fieldType := refStruct.Type().Field(i)
1,740✔
287
                if !fieldType.IsExported() {
2,256✔
288
                        continue
516✔
289
                }
290

291
                if fieldType.Name == "Location" {
1,332✔
292
                        continue
108✔
293
                }
294

295
                field := refStruct.Field(i)
1,116✔
296

1,116✔
297
                childInfo := w.walk(field.Interface())
1,116✔
298
                if childInfo.start == -1 || childInfo.end == -1 {
1,720✔
299
                        continue
604✔
300
                }
301
                info = info.addChild(fieldType.Name, childInfo)
512✔
302
        }
303

304
        return w.balanceParenthesis(info)
472✔
305
}
306

307
func (w *walker) walkNullTest(a *pg.NullTest) nodeInfo {
×
308
        info := w.reflectWalk(reflect.ValueOf(a))
×
309
        nullInfo := w.findTokenAfter(info.end, pg.Token_NULL_P)
×
310
        if nullInfo.end != -1 {
×
311
                info.end = nullInfo.end
×
312
        }
×
313
        w.setNull(info.children["Arg"].position(), alwaysNullable{})
×
314

×
315
        return info
×
316
}
317

318
func (w *walker) walkAConst(a *pg.A_Const) nodeInfo {
×
319
        w.updatePosition(a.Location)
×
320
        info := nodeInfo{
×
321
                start:    a.Location,
×
322
                end:      w.getEnd(a.Location),
×
323
                children: map[string]nodeInfo{},
×
324
        }
×
325
        w.maybeSetName(info.position(), w.input[info.start:info.end])
×
326
        return info
×
327
}
×
328

329
func (w *walker) walkSelectStmt(a *pg.SelectStmt) nodeInfo {
60✔
330
        if a == nil {
100✔
331
                return newNodeInfo()
40✔
332
        }
40✔
333

334
        info := w.reflectWalk(reflect.ValueOf(a))
20✔
335
        info.start = w.getStartOfTokenBefore(info.start, pg.Token_SELECT, pg.Token_VALUES)
20✔
336

20✔
337
        if err := verifySelectStatement(a, info); err != nil {
20✔
338
                w.errors = append(w.errors, err)
×
339
        }
×
340

341
        valsInfo := info.children["ValuesLists"]
20✔
342
        for i := range a.ValuesLists {
32✔
343
                valInfo := valsInfo.children[strconv.Itoa(i)]
12✔
344
                w.editRules = append(w.editRules, internal.RecordPoints(
12✔
345
                        int(valInfo.start), int(valInfo.end-1),
12✔
346
                        func(start, end int) error {
24✔
347
                                w.setGroup(argPos{
12✔
348
                                        original: valInfo.position(),
12✔
349
                                        edited:   [2]int{start, end},
12✔
350
                                })
12✔
351
                                if len(a.ValuesLists) == 1 {
16✔
352
                                        w.setMultiple([2]int{start, end})
4✔
353
                                }
4✔
354
                                return nil
12✔
355
                        },
356
                )...)
357
        }
358

359
        return info
20✔
360
}
361

362
func (w *walker) walkInsertStmt(a *pg.InsertStmt) nodeInfo {
12✔
363
        info := w.reflectWalk(reflect.ValueOf(a))
12✔
364
        info.start = w.getStartOfTokenBefore(info.start, pg.Token_INSERT)
12✔
365

12✔
366
        vals := a.GetSelectStmt().GetSelectStmt().GetValuesLists()
12✔
367
        if len(vals) == 0 {
16✔
368
                return info
4✔
369
        }
4✔
370

371
        colNames := make([]string, len(a.Cols))
8✔
372
        for i := range a.Cols {
24✔
373
                colNameInfo := info.children["Cols"].children[strconv.Itoa(i)]
16✔
374
                colNames[i] = w.names[colNameInfo.position()]
16✔
375
        }
16✔
376

377
        table := w.getTableSource(a.Relation, info.children["Relation"])
8✔
378
        if len(a.Cols) == 0 {
8✔
379
                colNames = make([]string, len(table.columns))
×
380
                for i := range table.columns {
×
381
                        colNames[i] = table.columns[i].name
×
382
                }
×
383
        }
384

385
        valsInfo := info.
8✔
386
                children["SelectStmt"].
8✔
387
                children["SelectStmt"].
8✔
388
                children["ValuesLists"]
8✔
389

8✔
390
        for i := range vals {
20✔
391
                itemsInfo := valsInfo.
12✔
392
                        children[strconv.Itoa(i)].
12✔
393
                        children["List"].
12✔
394
                        children["Items"]
12✔
395

12✔
396
                for colIndex := range colNames {
36✔
397
                        itemInfo, hasInfo := itemsInfo.children[strconv.Itoa(colIndex)]
24✔
398
                        if !hasInfo {
24✔
399
                                continue
×
400
                        }
401
                        name := colNames[colIndex]
24✔
402
                        w.maybeSetName(itemInfo.position(), name)
24✔
403
                        for _, col := range table.columns {
132✔
404
                                if col.name == name && col.nullable {
120✔
405
                                        w.setNull(itemInfo.position(), alwaysNullable{})
12✔
406
                                        break
12✔
407
                                }
408
                        }
409
                }
410
        }
411

412
        return info
8✔
413
}
414

415
func (w *walker) walkUpdateStmt(a *pg.UpdateStmt) nodeInfo {
4✔
416
        info := w.reflectWalk(reflect.ValueOf(a))
4✔
417
        info.start = w.getStartOfTokenBefore(info.start, pg.Token_UPDATE)
4✔
418

4✔
419
        if err := verifyUpdateStatement(a, info); err != nil {
4✔
420
                w.errors = append(w.errors, err)
×
421
        }
×
422

423
        return info
4✔
424
}
425

426
func (w *walker) walkDeleteStmt(a *pg.DeleteStmt) nodeInfo {
4✔
427
        info := w.reflectWalk(reflect.ValueOf(a))
4✔
428
        info.start = w.getStartOfTokenBefore(info.start, pg.Token_DELETE_P)
4✔
429

4✔
430
        if err := verifyDeleteStatement(a, info); err != nil {
4✔
431
                w.errors = append(w.errors, err)
×
432
        }
×
433

434
        return info
4✔
435
}
436

437
func (w *walker) walkParamRef(a *pg.ParamRef) nodeInfo {
48✔
438
        w.updatePosition(a.Location)
48✔
439
        info := nodeInfo{
48✔
440
                start:    a.Location,
48✔
441
                end:      w.getEnd(a.Location),
48✔
442
                children: map[string]nodeInfo{},
48✔
443
        }
48✔
444
        if len(w.args) < int(a.Number) {
96✔
445
                w.args = append(w.args, make([][]argPos, int(a.Number)-len(w.args))...)
48✔
446
        }
48✔
447
        w.editRules = append(w.editRules, internal.EditCallback(
48✔
448
                internal.ReplaceFromFunc(
48✔
449
                        int(info.start), int(info.end-1),
48✔
450
                        func() string {
96✔
451
                                return fmt.Sprintf("$%d", w.atom.Add(1))
48✔
452
                        },
48✔
453
                ),
454
                func(start, end int, _, _ string) error {
48✔
455
                        w.args[a.Number-1] = append(w.args[a.Number-1], argPos{
48✔
456
                                original: info.position(),
48✔
457
                                edited:   [2]int{start, end},
48✔
458
                        })
48✔
459
                        return nil
48✔
460
                }),
48✔
461
        )
462

463
        return info
48✔
464
}
465

466
func (w *walker) walkAExpr(a *pg.A_Expr) nodeInfo {
20✔
467
        info := w.reflectWalk(reflect.ValueOf(a))
20✔
468
        lInfo := info.children["Lexpr"]
20✔
469
        rInfo := info.children["Rexpr"]
20✔
470
        switch a.Kind {
20✔
471
        case pg.A_Expr_Kind_AEXPR_OP,
472
                pg.A_Expr_Kind_AEXPR_DISTINCT,
473
                pg.A_Expr_Kind_AEXPR_NOT_DISTINCT:
8✔
474
                w.matchNames(lInfo.position(), rInfo.position())
8✔
475
        case pg.A_Expr_Kind_AEXPR_OP_ANY, pg.A_Expr_Kind_AEXPR_OP_ALL:
×
476
                for _, argInfo := range rInfo.children["AArrayExpr"].children {
×
477
                        w.matchNames(lInfo.position(), argInfo.position())
×
478
                }
×
479
        case pg.A_Expr_Kind_AEXPR_IN:
12✔
480
                lRow, isRow := lInfo.children["RowExpr"].children["Args"]
12✔
481
                for _, argInfo := range rInfo.children["List"].children["Items"].children {
24✔
482
                        w.matchNames(lInfo.position(), argInfo.position())
12✔
483
                        if !isRow {
24✔
484
                                continue
12✔
485
                        }
486
                        for key, rowItem := range argInfo.children["RowExpr"].children["Args"].children {
×
487
                                w.matchNames(lRow.children[key].position(), rowItem.position())
×
488
                        }
×
489
                }
490
        }
491

492
        return info
20✔
493
}
494

495
func (w *walker) walkColumnRef(a *pg.ColumnRef) nodeInfo {
40✔
496
        info := w.reflectWalk(reflect.ValueOf(a))
40✔
497
        if len(a.Fields) > 0 {
80✔
498
                lastInfo := info.children["Fields"].children[strconv.Itoa(len(a.Fields)-1)]
40✔
499
                if lastInfo.isValid() {
80✔
500
                        w.maybeSetName(info.position(), w.names[lastInfo.position()])
40✔
501
                }
40✔
502
        }
503
        w.setNull(info.position(), columnNullable{a, info})
40✔
504

40✔
505
        return info
40✔
506
}
507

508
func (w *walker) walkResTarget(a *pg.ResTarget) nodeInfo {
48✔
509
        w.updatePosition(a.Location)
48✔
510
        info := w.reflectWalk(reflect.ValueOf(a))
48✔
511

48✔
512
        if a.Name != "" {
76✔
513
                nameInfo := newNodeInfo()
28✔
514
                index := sort.Search(len(w.tokens)-1, func(i int) bool {
148✔
515
                        return w.tokens[i].End > info.end
120✔
516
                })
120✔
517

518
        IndexLoop:
28✔
519
                for i := index; i < len(w.tokens); i++ {
56✔
520
                        switch {
28✔
521
                        case w.tokens[i].Token == pg.Token_IDENT ||
522
                                w.tokens[i].KeywordKind == pg.KeywordKind_UNRESERVED_KEYWORD:
×
523
                                nameInfo = nodeInfo{
×
524
                                        start: w.tokens[i].Start,
×
525
                                        end:   w.tokens[i].End,
×
526
                                }
×
527

528
                        case w.tokens[i].Token != pg.Token_AS:
28✔
529
                                break IndexLoop
28✔
530
                        }
531
                }
532

533
                info = info.addChild("Name", nameInfo)
28✔
534
                w.maybeSetName(info.position(), a.Name)
28✔
535
        }
536

537
        valPos := info.children["Val"].position()
48✔
538
        w.maybeSetName(info.position(), w.names[valPos])
48✔
539
        w.setNull(info.position(), w.nullability[valPos])
48✔
540

48✔
541
        if a.Name != "" {
76✔
542
                w.maybeSetName(valPos, a.Name)
28✔
543
        }
28✔
544

545
        return info
48✔
546
}
547

548
func (w *walker) walkRangeVar(a *pg.RangeVar) nodeInfo {
32✔
549
        w.updatePosition(a.Location)
32✔
550
        info := newNodeInfo()
32✔
551
        firstInfo := nodeInfo{
32✔
552
                start:    a.Location,
32✔
553
                end:      w.getEnd(a.Location),
32✔
554
                children: map[string]nodeInfo{},
32✔
555
        }
32✔
556
        switch {
32✔
557
        case a.Catalogname != "":
×
558
                catalogInfo := firstInfo
×
559
                schemaInfo := w.findIdentOrUnreserved(catalogInfo.end)
×
560
                relInfo := w.findIdentOrUnreserved(schemaInfo.end)
×
561

×
562
                w.maybeSetName(catalogInfo.position(), a.Catalogname)
×
563
                w.maybeSetName(schemaInfo.position(), a.Schemaname)
×
564
                w.maybeSetName(relInfo.position(), a.Relname)
×
565

×
566
                info = info.addChild("Catalogname", catalogInfo)
×
567
                info = info.addChild("Schemaname", schemaInfo)
×
568
                info = info.addChild("Relname", relInfo)
×
569

570
        case a.Schemaname != "":
×
571
                schemaInfo := firstInfo
×
572
                relInfo := w.findIdentOrUnreserved(schemaInfo.end)
×
573

×
574
                w.maybeSetName(schemaInfo.position(), a.Schemaname)
×
575
                w.maybeSetName(relInfo.position(), a.Relname)
×
576

×
577
                info = info.addChild("Schemaname", schemaInfo)
×
578
                info = info.addChild("Relname", relInfo)
×
579
        default:
32✔
580
                w.maybeSetName(firstInfo.position(), a.Relname)
32✔
581
                info = info.addChild("Relname", firstInfo)
32✔
582
        }
583

584
        w.position = info.end
32✔
585
        info = info.addChild("Alias", w.walk(a.Alias))
32✔
586

32✔
587
        return info
32✔
588
}
589

590
func (w *walker) walkAlias(a *pg.Alias) nodeInfo {
32✔
591
        if a == nil {
64✔
592
                return newNodeInfo()
32✔
593
        }
32✔
594
        aliasNameInfo := w.findIdentOrUnreserved(w.position)
×
595
        info := newNodeInfo().addChild("Aliasname", aliasNameInfo)
×
596
        w.maybeSetName(aliasNameInfo.position(), a.Aliasname)
×
597

×
598
        // Update position so that the col name identifiers can be found
×
599
        w.updatePosition(aliasNameInfo.end)
×
600
        info = info.addChild("Colnames", w.walk(a.GetColnames()))
×
601
        info = w.balanceParenthesis(info)
×
602

×
603
        return info
×
604
}
605

606
func (w *walker) walkString(a *pg.String) nodeInfo {
56✔
607
        info := newNodeInfo()
56✔
608
        identifierInfo := w.findIdentOrUnreserved(w.position)
56✔
609

56✔
610
        if !identifierInfo.isValid() {
72✔
611
                return info
16✔
612
        }
16✔
613

614
        quoted := w.input[identifierInfo.start:identifierInfo.end]
40✔
615
        unquoted, err := strconv.Unquote(quoted)
40✔
616
        if err != nil {
80✔
617
                unquoted = quoted
40✔
618
        }
40✔
619
        if strings.EqualFold(a.GetSval(), unquoted) {
76✔
620
                info = identifierInfo
36✔
621
                w.maybeSetName(info.position(), unquoted)
36✔
622
        }
36✔
623

624
        return info
40✔
625
}
626

627
func (w *walker) walkSortBy(a *pg.SortBy) nodeInfo {
×
628
        w.updatePosition(a.Location)
×
629
        info := w.reflectWalk(reflect.ValueOf(a))
×
630
        hasSortDir := a.SortbyDir > pg.SortByDir_SORTBY_DEFAULT
×
631
        hasSortNulls := a.SortbyNulls > pg.SortByNulls_SORTBY_NULLS_DEFAULT
×
632
        switch {
×
633
        case hasSortNulls:
×
634
                info.end = w.getEndOfTokenAfter(
×
635
                        info.start, pg.Token_FIRST_P, pg.Token_LAST_P)
×
636
        case hasSortDir && a.SortbyDir != pg.SortByDir_SORTBY_USING:
×
637
                info.end = w.getEndOfTokenAfter(
×
638
                        info.start, pg.Token_ASC, pg.Token_DESC)
×
639
        }
640
        return info
×
641
}
642

643
func (w *walker) walkFuncCall(a *pg.FuncCall) nodeInfo {
×
644
        info := w.reflectWalk(reflect.ValueOf(a))
×
NEW
645
        info.end = w.getEndOfTokenAfter(info.end, closeParToken)
×
646
        if len(a.Funcname) > 0 {
×
647
                funcNameInfo := info.children["Funcname"].children["0"]
×
648
                if funcNameInfo.isValid() {
×
649
                        w.maybeSetName(info.position(), w.names[funcNameInfo.position()])
×
650
                }
×
651
        }
652

653
        return info
×
654
}
655

656
func (w *walker) walkList(a *pg.List) nodeInfo {
24✔
657
        info := w.reflectWalk(reflect.ValueOf(a))
24✔
658
        info.start = w.getStartOfTokenBefore(info.start, openParToken)
24✔
659
        info.end = w.getEndOfTokenAfter(info.end, closeParToken)
24✔
660

24✔
661
        w.editRules = append(w.editRules, internal.RecordPoints(
24✔
662
                int(info.start), int(info.end-1),
24✔
663
                func(start, end int) error {
48✔
664
                        w.setGroup(argPos{
24✔
665
                                original: info.position(),
24✔
666
                                edited:   [2]int{start, end},
24✔
667
                        })
24✔
668
                        return nil
24✔
669
                },
24✔
670
        )...)
671

672
        itemsInfo := info.children["Items"]
24✔
673
        if len(a.Items) == 1 {
36✔
674
                w.editRules = append(w.editRules, internal.RecordPoints(
12✔
675
                        int(itemsInfo.start), int(itemsInfo.end-1),
12✔
676
                        func(start, end int) error {
24✔
677
                                w.setMultiple([2]int{start, end})
12✔
678
                                return nil
12✔
679
                        },
12✔
680
                )...)
681
        }
682

683
        return info
24✔
684
}
685

686
func (w *walker) walkRowExpr(a *pg.RowExpr) nodeInfo {
×
687
        info := w.reflectWalk(reflect.ValueOf(a))
×
688
        w.editRules = append(w.editRules,
×
689
                internal.RecordPoints(int(info.start), int(info.end-1),
×
690
                        func(start, end int) error {
×
691
                                w.setGroup(argPos{
×
692
                                        original: info.position(),
×
693
                                        edited:   [2]int{start, end},
×
694
                                })
×
695
                                return nil
×
696
                        },
×
697
                )...)
698

699
        return info
×
700
}
701

702
func (w *walker) walkAArrayExpr(a *pg.A_ArrayExpr) nodeInfo {
×
703
        info := w.reflectWalk(reflect.ValueOf(a))
×
704
        info.end = w.getEndOfTokenAfter(info.end, pg.Token_ASCII_93)
×
705

×
706
        elementsInfo := info.children["Elements"]
×
707
        if len(a.Elements) == 1 {
×
708
                w.editRules = append(w.editRules, internal.RecordPoints(
×
709
                        int(elementsInfo.start), int(elementsInfo.end-1),
×
710
                        func(start, end int) error {
×
711
                                w.setMultiple([2]int{start, end})
×
712
                                w.setGroup(argPos{
×
713
                                        original: elementsInfo.position(),
×
714
                                        edited:   [2]int{start, end},
×
715
                                })
×
716
                                return nil
×
717
                        },
×
718
                )...)
719
        } else {
×
720
                w.editRules = append(w.editRules, internal.RecordPoints(
×
721
                        int(info.start), int(info.end-1),
×
722
                        func(start, end int) error {
×
723
                                w.setGroup(argPos{
×
724
                                        original: info.position(),
×
725
                                        edited:   [2]int{start, end},
×
726
                                })
×
727
                                return nil
×
728
                        },
×
729
                )...)
730
        }
731

732
        return info
×
733
}
734

735
func (w *walker) walkOnConflictClause(a *pg.OnConflictClause) nodeInfo {
12✔
736
        info := w.reflectWalk(reflect.ValueOf(a))
12✔
737

12✔
738
        var doIndex, actionIndex int
12✔
739
        lastInfo := w.findTokenAfterFunc(info.start, func(index int, t *pg.ScanToken) bool {
12✔
740
                switch t.Token {
×
741
                case pg.Token_DO:
×
742
                        if t.KeywordKind == pg.KeywordKind_RESERVED_KEYWORD {
×
743
                                doIndex = index
×
744
                        }
×
745
                case pg.Token_UPDATE, pg.Token_NOTHING:
×
746
                        if t.KeywordKind == pg.KeywordKind_UNRESERVED_KEYWORD {
×
747
                                actionIndex = index
×
748
                        }
×
749
                }
750

751
                return actionIndex-doIndex == 1
×
752
        })
753

754
        if lastInfo.isValid() {
12✔
755
                info = info.addChild("Action", nodeInfo{w.tokens[doIndex].Start, w.tokens[actionIndex].End, nil})
×
756
        }
×
757

758
        return info
12✔
759
}
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