-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
main.go
105 lines (86 loc) · 2.67 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package operatingsystemversion
import (
"strings"
v "github.com/RussellLuo/validating/v3"
"gorm.io/gorm"
"github.com/th0th/poeticmetric/backend/pkg/depot"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/filter"
"github.com/th0th/poeticmetric/backend/pkg/service/sitereport/pagination"
)
type Datum struct {
OperatingSystemName string `json:"operatingSystemName"`
OperatingSystemVersion string `json:"operatingSystemVersion"`
VisitorCount uint64 `json:"visitorCount"`
VisitorPercentage uint16 `json:"visitorPercentage"`
}
type PaginationCursor struct {
OperatingSystemVersion string `json:"operatingSystemVersion"`
VisitorCount uint64 `json:"visitorCount"`
}
type Report struct {
Data []*Datum `json:"data"`
PaginationCursor *PaginationCursor `json:"paginationCursor"`
}
func Get(dp *depot.Depot, filters *filter.Filters, paginationCursor *PaginationCursor) (*Report, error) {
err := validateFilters(filters)
if err != nil {
return nil, err
}
report := &Report{}
baseQuery := filter.Apply(dp, filters).
Where("operating_system_version is not null")
totalVisitorCountSubQuery := baseQuery.
Session(&gorm.Session{}).
Select("count(distinct visitor_id)")
baseSubQuery := baseQuery.
Session(&gorm.Session{}).
Select(
strings.Join([]string{
"operating_system_name",
"operating_system_version",
"count(distinct visitor_id) as visitor_count",
"toUInt16(round(100 * visitor_count / (@totalVisitorCountSubQuery))) as visitor_percentage",
}, ", "),
map[string]any{
"totalVisitorCountSubQuery": totalVisitorCountSubQuery,
},
).
Group("operating_system_name, operating_system_version").
Order("visitor_count desc, operating_system_version")
query := dp.ClickHouse().
Table("(?)", baseSubQuery)
if paginationCursor != nil {
query.
Where(
"(visitor_count = ? and operating_system_version > ?) or visitor_count < ?",
paginationCursor.VisitorCount,
paginationCursor.OperatingSystemVersion,
paginationCursor.VisitorCount,
)
}
err = query.
Limit(pagination.Size).
Find(&report.Data).
Error
if err != nil {
return nil, err
}
if len(report.Data) == pagination.Size {
report.PaginationCursor = &PaginationCursor{
OperatingSystemVersion: report.Data[pagination.Size-1].OperatingSystemVersion,
VisitorCount: report.Data[pagination.Size-1].VisitorCount,
}
}
return report, nil
}
func validateFilters(filters *filter.Filters) error {
errs := v.Validate(v.Schema{
v.F("operatingSystemName", filters.OperatingSystemName): v.All(
v.Nonzero[*string]().Msg("This field is required."),
),
})
if len(errs) > 0 {
return errs
}
return nil
}