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

stephenafamo / bob / 14351235503

09 Apr 2025 07:14AM UTC coverage: 47.87% (-1.5%) from 49.32%
14351235503

Pull #388

github

stephenafamo
Implement parsing of SQLite SELECT queries
Pull Request #388: Implement parsing of SQLite SELECT queries

1093 of 2670 new or added lines in 29 files covered. (40.94%)

4 existing lines in 4 files now uncovered.

7471 of 15607 relevant lines covered (47.87%)

240.65 hits per line

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

0.0
/dialect/sqlite/view.go
1
package sqlite
2

3
import (
4
        "context"
5
        "fmt"
6
        "reflect"
7

8
        "github.com/stephenafamo/bob"
9
        "github.com/stephenafamo/bob/dialect/sqlite/dialect"
10
        "github.com/stephenafamo/bob/dialect/sqlite/sm"
11
        "github.com/stephenafamo/bob/internal"
12
        "github.com/stephenafamo/bob/internal/mappings"
13
        "github.com/stephenafamo/bob/orm"
14
        "github.com/stephenafamo/scan"
15
)
16

17
// UseSchema modifies a context to add a schema that will be used when
18
// a tablle/view was generated with an empty schema
19
func UseSchema(ctx context.Context, schema string) context.Context {
×
20
        return context.WithValue(ctx, orm.CtxUseSchema, schema)
×
21
}
×
22

23
func NewView[T any](schema, tableName string) *View[T, []T] {
×
24
        return NewViewx[T, []T](schema, tableName)
×
25
}
×
26

27
func NewViewx[T any, Tslice ~[]T](schema, tableName string) *View[T, Tslice] {
×
28
        v, _ := newView[T, Tslice](schema, tableName)
×
29
        return v
×
30
}
×
31

32
func newView[T any, Tslice ~[]T](schema, tableName string) (*View[T, Tslice], mappings.Mapping) {
×
33
        var zero T
×
34

×
35
        mappings := mappings.GetMappings(reflect.TypeOf(zero))
×
36
        alias := tableName
×
37
        if schema != "" {
×
38
                alias = fmt.Sprintf("%s.%s", schema, tableName)
×
39
        }
×
40

41
        allCols := internal.MappingCols(mappings, alias)
×
42

×
43
        return &View[T, Tslice]{
×
44
                schema:  schema,
×
45
                name:    tableName,
×
46
                alias:   alias,
×
47
                allCols: allCols,
×
48
                scanner: scan.StructMapper[T](),
×
49
        }, mappings
×
50
}
51

52
type View[T any, Tslice ~[]T] struct {
53
        schema string
54
        name   string
55
        alias  string
56

57
        allCols orm.Columns
58
        scanner scan.Mapper[T]
59

60
        AfterSelectHooks bob.Hooks[Tslice, bob.SkipModelHooksKey]
61
        SelectQueryHooks bob.Hooks[*dialect.SelectQuery, bob.SkipQueryHooksKey]
62
}
63

64
func (v *View[T, Tslice]) Name() Expression {
×
65
        // schema is not empty, never override
×
66
        if v.schema != "" {
×
67
                return Quote(v.schema, v.name)
×
68
        }
×
69

70
        return Expression{}.New(orm.SchemaTable(v.name))
×
71
}
72

73
func (v *View[T, Tslice]) NameAs() bob.Expression {
×
74
        return v.Name().As(v.alias)
×
75
}
×
76

77
func (v *View[T, Tslice]) Alias() string {
×
78
        return v.alias
×
79
}
×
80

81
// Returns a column list
82
func (v *View[T, Tslice]) Columns() orm.Columns {
×
83
        // get the schema
×
84
        return v.allCols
×
85
}
×
86

87
// Starts a select query
88
func (v *View[T, Tslice]) Query(queryMods ...bob.Mod[*dialect.SelectQuery]) *ViewQuery[T, Tslice] {
×
89
        q := &ViewQuery[T, Tslice]{
×
90
                Query: orm.Query[*dialect.SelectQuery, T, Tslice]{
×
91
                        ExecQuery: orm.ExecQuery[*dialect.SelectQuery]{
×
92
                                BaseQuery: Select(sm.From(v.NameAs())),
×
93
                                Hooks:     &v.SelectQueryHooks,
×
94
                        },
×
95
                        Scanner: v.scanner,
×
96
                },
×
97
        }
×
98

×
99
        q.BaseQuery.Expression.AppendContextualModFunc(
×
100
                func(ctx context.Context, q *dialect.SelectQuery) (context.Context, error) {
×
101
                        if len(q.SelectList.Columns) == 0 {
×
102
                                q.AppendSelect(v.Columns())
×
103
                        }
×
104
                        return ctx, nil
×
105
                },
106
        )
107

108
        q.Apply(queryMods...)
×
109

×
110
        return q
×
111
}
112

113
type ViewQuery[T any, Ts ~[]T] struct {
114
        orm.Query[*dialect.SelectQuery, T, Ts]
115
}
116

117
// Count the number of matching rows
118
func (v *ViewQuery[T, Tslice]) Count(ctx context.Context, exec bob.Executor) (int64, error) {
×
119
        ctx, err := v.RunHooks(ctx, exec)
×
120
        if err != nil {
×
121
                return 0, err
×
122
        }
×
123
        return bob.One(ctx, exec, asCountQuery(v.BaseQuery), scan.SingleColumnMapper[int64])
×
124
}
125

126
// Exists checks if there is any matching row
127
func (v *ViewQuery[T, Tslice]) Exists(ctx context.Context, exec bob.Executor) (bool, error) {
×
128
        count, err := v.Count(ctx, exec)
×
129
        return count > 0, err
×
130
}
×
131

132
// asCountQuery clones and rewrites an existing query to a count query
133
func asCountQuery(query bob.BaseQuery[*dialect.SelectQuery]) bob.BaseQuery[*dialect.SelectQuery] {
×
134
        // clone the original query, so it's not being modified silently
×
135
        countQuery := query.Clone()
×
136
        // only select the count
×
137
        countQuery.Expression.SetSelect("count(1)")
×
138
        // don't select any preload columns
×
139
        countQuery.Expression.SetPreloadSelect()
×
140
        // disable mapper mods
×
141
        countQuery.Expression.SetMapperMods()
×
142
        // disable loaders
×
143
        countQuery.Expression.SetLoaders()
×
144
        // set the limit to 1
×
145
        countQuery.Expression.SetLimit(1)
×
146
        // remove ordering
×
NEW
147
        countQuery.Expression.ClearOrderBy()
×
148
        // remove group by
×
149
        countQuery.Expression.SetGroups()
×
150
        // remove offset
×
151
        countQuery.Expression.SetOffset(0)
×
152

×
153
        return countQuery
×
154
}
×
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

© 2026 Coveralls, Inc