2024-03-15 12:31:12 +00:00
|
|
|
|
package statistics
|
|
|
|
|
|
|
|
|
|
import (
|
2024-03-15 13:02:09 +00:00
|
|
|
|
"context"
|
2024-03-15 12:31:12 +00:00
|
|
|
|
"database/sql"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen"
|
2024-03-16 20:04:33 +00:00
|
|
|
|
"time"
|
2024-03-15 12:31:12 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Deps struct {
|
|
|
|
|
Queries *sqlcgen.Queries
|
|
|
|
|
Pool *sql.DB
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type StatisticsRepository struct {
|
|
|
|
|
queries *sqlcgen.Queries
|
|
|
|
|
pool *sql.DB
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewStatisticsRepo(deps Deps) *StatisticsRepository {
|
|
|
|
|
return &StatisticsRepository{
|
|
|
|
|
queries: deps.Queries,
|
|
|
|
|
pool: deps.Pool,
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-15 13:02:09 +00:00
|
|
|
|
|
|
|
|
|
type DeviceStatReq struct {
|
2024-03-15 13:36:41 +00:00
|
|
|
|
QuizId int64
|
2024-03-15 13:02:09 +00:00
|
|
|
|
From uint64
|
|
|
|
|
To uint64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type DeviceStatResp struct {
|
2024-03-15 13:36:41 +00:00
|
|
|
|
//ключ DeviceType значение процент
|
2024-03-18 09:09:47 +00:00
|
|
|
|
Device map[string]float64 // процентное соотношение DeviceType по всем ответам на опроc c res==true
|
2024-03-15 13:36:41 +00:00
|
|
|
|
// тоже самое тут только по OS и BROWSER
|
2024-03-18 09:09:47 +00:00
|
|
|
|
OS map[string]float64
|
|
|
|
|
Browser map[string]float64
|
2024-03-15 13:02:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-15 13:36:41 +00:00
|
|
|
|
func (r *StatisticsRepository) GetDeviceStatistics(ctx context.Context, req DeviceStatReq) (DeviceStatResp, error) {
|
2024-03-15 13:02:09 +00:00
|
|
|
|
resp := DeviceStatResp{
|
2024-03-18 09:09:47 +00:00
|
|
|
|
Device: make(map[string]float64),
|
|
|
|
|
OS: make(map[string]float64),
|
|
|
|
|
Browser: make(map[string]float64),
|
2024-03-15 13:02:09 +00:00
|
|
|
|
}
|
2024-03-15 13:36:41 +00:00
|
|
|
|
|
|
|
|
|
allStatistics, err := r.queries.DeviceStatistics(ctx, sqlcgen.DeviceStatisticsParams{
|
|
|
|
|
QuizID: req.QuizId,
|
|
|
|
|
ToTimestamp: float64(req.From),
|
|
|
|
|
ToTimestamp_2: float64(req.To),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return resp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, stat := range allStatistics {
|
2024-03-17 11:07:08 +00:00
|
|
|
|
resp.Device[stat.DeviceType] = stat.DevicePercentage
|
|
|
|
|
resp.OS[stat.Os] = stat.OsPercentage
|
|
|
|
|
resp.Browser[stat.Browser] = stat.BrowserPercentage
|
2024-03-15 13:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp, nil
|
2024-03-15 13:02:09 +00:00
|
|
|
|
}
|
2024-03-15 16:28:22 +00:00
|
|
|
|
|
|
|
|
|
type GeneralStatsResp struct {
|
2024-03-17 11:07:08 +00:00
|
|
|
|
Open map[int64]int64 // количество ответов с полем start == true за период от одного пункта разбиения и до другого
|
|
|
|
|
Result map[int64]int64 // количество ответов с полем result == true за период от одного пункта разбиения и до другого
|
|
|
|
|
AvTime map[int64]uint64 // среднее время между ответом с полем result == true и start == true. в рамках сессии
|
|
|
|
|
Conversion map[int64]int32 // Result/Open за период от одного пункта разбиения и до другого
|
2024-03-15 16:28:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *StatisticsRepository) GetGeneralStatistics(ctx context.Context, req DeviceStatReq) (GeneralStatsResp, error) {
|
2024-03-15 17:19:39 +00:00
|
|
|
|
resp := GeneralStatsResp{
|
2024-03-17 11:07:08 +00:00
|
|
|
|
Open: make(map[int64]int64),
|
|
|
|
|
Result: make(map[int64]int64),
|
|
|
|
|
AvTime: make(map[int64]uint64),
|
|
|
|
|
Conversion: make(map[int64]int32),
|
2024-03-15 17:19:39 +00:00
|
|
|
|
}
|
2024-03-16 20:58:01 +00:00
|
|
|
|
// todo затестить запрос нужно, когда на один тру ответ приходится один тру старт апдейтнуть запрос
|
2024-03-15 17:19:39 +00:00
|
|
|
|
allStatistics, err := r.queries.GeneralStatistics(ctx, sqlcgen.GeneralStatisticsParams{
|
2024-03-16 20:04:33 +00:00
|
|
|
|
QuizID: req.QuizId,
|
|
|
|
|
Column1: time.Unix(int64(req.From), 0),
|
|
|
|
|
Column2: time.Unix(int64(req.To), 0),
|
2024-03-15 17:19:39 +00:00
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return resp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, stat := range allStatistics {
|
2024-03-17 11:07:08 +00:00
|
|
|
|
resp.Open[stat.TimeBucket.Unix()] = stat.OpenCount
|
2024-03-18 10:05:06 +00:00
|
|
|
|
resp.Result[stat.TimeBucket.Unix()] = stat.TrueResultCount
|
2024-03-17 11:07:08 +00:00
|
|
|
|
resp.AvTime[stat.TimeBucket.Unix()] = uint64(stat.AvgTime)
|
|
|
|
|
resp.Conversion[stat.TimeBucket.Unix()] = stat.Conversion
|
2024-03-15 17:19:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp, nil
|
2024-03-15 16:28:22 +00:00
|
|
|
|
}
|
2024-03-17 11:07:08 +00:00
|
|
|
|
|
|
|
|
|
type QuestionsStatsResp struct {
|
2024-03-17 15:17:57 +00:00
|
|
|
|
// PS это / не или а делить а то я спустя пару часов только догнал
|
2024-03-17 11:07:08 +00:00
|
|
|
|
//Funnel 3 отдельных метрики
|
|
|
|
|
// 0 - количество сессий с любым ответом кроме start == true / количество сессий с ответом start == true
|
|
|
|
|
// 1 - количество сессий с result == false, но тип вопроса, на который ответ == result / количество сессий с ответом start == true
|
|
|
|
|
// 2 - количество сессий с ответом result == true / количество сессий с ответом start == true
|
|
|
|
|
Funnel [3]float64
|
|
|
|
|
// ключ - заголовок вопроса найденного по айдишнику вопроса в ответе result == true,
|
|
|
|
|
// значение - процент ответов с result == true и таким айдишником вопроса
|
|
|
|
|
Results map[string]float64
|
|
|
|
|
// ключ - заголовок вопроса, а значение - map, где ключ - вариант ответа на этот вопрос,
|
|
|
|
|
// т.е. группировка по полю Контент, а значение - процент таких ответов
|
|
|
|
|
Questions map[string]map[string]float64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *StatisticsRepository) GetQuestionsStatistics(ctx context.Context, req DeviceStatReq) (QuestionsStatsResp, error) {
|
2024-03-17 15:17:57 +00:00
|
|
|
|
resp := QuestionsStatsResp{
|
|
|
|
|
Funnel: [3]float64{},
|
|
|
|
|
Results: make(map[string]float64),
|
|
|
|
|
Questions: make(map[string]map[string]float64),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
queStatistics, err := r.queries.QuestionsStatistics(ctx, sqlcgen.QuestionsStatisticsParams{
|
|
|
|
|
QuizID: req.QuizId,
|
|
|
|
|
ToTimestamp: float64(req.From),
|
|
|
|
|
ToTimestamp_2: float64(req.To),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return resp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, row := range queStatistics {
|
2024-03-17 16:38:19 +00:00
|
|
|
|
if row.CountStartTrue != 0 {
|
|
|
|
|
resp.Funnel[0] = float64(row.CountStartFalse) / float64(row.CountStartTrue)
|
|
|
|
|
resp.Funnel[1] = float64(row.CountFResultWithTQuestion) / float64(row.CountStartTrue)
|
|
|
|
|
resp.Funnel[2] = float64(row.CountTResult) / float64(row.CountStartTrue)
|
|
|
|
|
}
|
2024-03-17 15:17:57 +00:00
|
|
|
|
|
2024-03-17 19:39:52 +00:00
|
|
|
|
resp.Results[row.ResultsTitle] = row.ResultsPercentage
|
2024-03-17 11:07:08 +00:00
|
|
|
|
|
2024-03-17 15:17:57 +00:00
|
|
|
|
if resp.Questions[row.QuestionsTitle] == nil {
|
|
|
|
|
resp.Questions[row.QuestionsTitle] = make(map[string]float64)
|
|
|
|
|
}
|
2024-03-17 19:08:19 +00:00
|
|
|
|
resp.Questions[row.QuestionsTitle][row.AnswerContent.String] = row.QuestionsPercentage
|
2024-03-17 15:17:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp, nil
|
2024-03-17 11:07:08 +00:00
|
|
|
|
}
|
2024-03-25 08:30:06 +00:00
|
|
|
|
|
|
|
|
|
type StatisticResp struct {
|
|
|
|
|
// от from до to
|
|
|
|
|
Registrations uint64 // количество зарегестрированных аккаунтов
|
|
|
|
|
Quizes uint64 // количество созданных не удаленных квизов
|
|
|
|
|
Results uint64 // количество ответов с result = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *StatisticsRepository) AllServiceStatistics(ctx context.Context, from, to uint64) (StatisticResp, error) {
|
|
|
|
|
allSvcStats, err := r.queries.AllServiceStatistics
|
|
|
|
|
}
|