// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.21.0 // source: query.sql package database import ( "context" "database/sql" "strings" "time" ) const addActivity = `-- name: AddActivity :one INSERT INTO activity ( user_id, document_id, device_id, start_time, duration, current_page, total_pages ) VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING id, user_id, document_id, device_id, start_time, duration, current_page, total_pages, created_at ` type AddActivityParams struct { UserID string `json:"user_id"` DocumentID string `json:"document_id"` DeviceID string `json:"device_id"` StartTime time.Time `json:"start_time"` Duration int64 `json:"duration"` CurrentPage int64 `json:"current_page"` TotalPages int64 `json:"total_pages"` } func (q *Queries) AddActivity(ctx context.Context, arg AddActivityParams) (Activity, error) { row := q.db.QueryRowContext(ctx, addActivity, arg.UserID, arg.DocumentID, arg.DeviceID, arg.StartTime, arg.Duration, arg.CurrentPage, arg.TotalPages, ) var i Activity err := row.Scan( &i.ID, &i.UserID, &i.DocumentID, &i.DeviceID, &i.StartTime, &i.Duration, &i.CurrentPage, &i.TotalPages, &i.CreatedAt, ) return i, err } const createUser = `-- name: CreateUser :execrows INSERT INTO users (id, pass) VALUES (?, ?) ON CONFLICT DO NOTHING ` type CreateUserParams struct { ID string `json:"id"` Pass string `json:"-"` } func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (int64, error) { result, err := q.db.ExecContext(ctx, createUser, arg.ID, arg.Pass) if err != nil { return 0, err } return result.RowsAffected() } const deleteDocument = `-- name: DeleteDocument :execrows UPDATE documents SET deleted = 1 WHERE id = ?1 ` func (q *Queries) DeleteDocument(ctx context.Context, id string) (int64, error) { result, err := q.db.ExecContext(ctx, deleteDocument, id) if err != nil { return 0, err } return result.RowsAffected() } const getActivity = `-- name: GetActivity :many SELECT id, user_id, document_id, device_id, start_time, duration, current_page, total_pages, created_at FROM activity WHERE user_id = ?1 AND ( (?2 = TRUE AND document_id = ?3) OR ?2 = FALSE ) ORDER BY start_time DESC LIMIT ?5 OFFSET ?4 ` type GetActivityParams struct { UserID string `json:"user_id"` DocFilter interface{} `json:"doc_filter"` DocumentID string `json:"document_id"` Offset int64 `json:"offset"` Limit int64 `json:"limit"` } func (q *Queries) GetActivity(ctx context.Context, arg GetActivityParams) ([]Activity, error) { rows, err := q.db.QueryContext(ctx, getActivity, arg.UserID, arg.DocFilter, arg.DocumentID, arg.Offset, arg.Limit, ) if err != nil { return nil, err } defer rows.Close() var items []Activity for rows.Next() { var i Activity if err := rows.Scan( &i.ID, &i.UserID, &i.DocumentID, &i.DeviceID, &i.StartTime, &i.Duration, &i.CurrentPage, &i.TotalPages, &i.CreatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getDailyReadStats = `-- name: GetDailyReadStats :many WITH RECURSIVE last_30_days (date) AS ( SELECT date('now') AS date UNION ALL SELECT date(date, '-1 days') FROM last_30_days LIMIT 30 ), activity_records AS ( SELECT sum(duration) AS seconds_read, date(start_time, 'localtime') AS day FROM activity WHERE user_id = ?1 GROUP BY day ORDER BY day DESC LIMIT 30 ) SELECT CAST(date AS TEXT), CAST(CASE WHEN seconds_read IS NULL THEN 0 ELSE seconds_read / 60 END AS INTEGER) AS minutes_read FROM last_30_days LEFT JOIN activity_records ON activity_records.day == last_30_days.date ORDER BY date DESC LIMIT 30 ` type GetDailyReadStatsRow struct { Date string `json:"date"` MinutesRead int64 `json:"minutes_read"` } func (q *Queries) GetDailyReadStats(ctx context.Context, userID string) ([]GetDailyReadStatsRow, error) { rows, err := q.db.QueryContext(ctx, getDailyReadStats, userID) if err != nil { return nil, err } defer rows.Close() var items []GetDailyReadStatsRow for rows.Next() { var i GetDailyReadStatsRow if err := rows.Scan(&i.Date, &i.MinutesRead); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getDatabaseInfo = `-- name: GetDatabaseInfo :one SELECT (SELECT count(rowid) FROM activity WHERE activity.user_id = ?1) AS activity_size, (SELECT count(rowid) FROM documents) AS documents_size, (SELECT count(rowid) FROM document_progress WHERE document_progress.user_id = ?1) AS progress_size, (SELECT count(rowid) FROM devices WHERE devices.user_id = ?1) AS devices_size LIMIT 1 ` type GetDatabaseInfoRow struct { ActivitySize int64 `json:"activity_size"` DocumentsSize int64 `json:"documents_size"` ProgressSize int64 `json:"progress_size"` DevicesSize int64 `json:"devices_size"` } func (q *Queries) GetDatabaseInfo(ctx context.Context, userID string) (GetDatabaseInfoRow, error) { row := q.db.QueryRowContext(ctx, getDatabaseInfo, userID) var i GetDatabaseInfoRow err := row.Scan( &i.ActivitySize, &i.DocumentsSize, &i.ProgressSize, &i.DevicesSize, ) return i, err } const getDeletedDocuments = `-- name: GetDeletedDocuments :many SELECT documents.id FROM documents WHERE documents.deleted = true AND documents.id IN (/*SLICE:document_ids*/?) ` func (q *Queries) GetDeletedDocuments(ctx context.Context, documentIds []string) ([]string, error) { query := getDeletedDocuments var queryParams []interface{} if len(documentIds) > 0 { for _, v := range documentIds { queryParams = append(queryParams, v) } query = strings.Replace(query, "/*SLICE:document_ids*/?", strings.Repeat(",?", len(documentIds))[1:], 1) } else { query = strings.Replace(query, "/*SLICE:document_ids*/?", "NULL", 1) } rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } defer rows.Close() var items []string for rows.Next() { var id string if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getDevice = `-- name: GetDevice :one SELECT id, user_id, device_name, created_at, sync FROM devices WHERE id = ?1 LIMIT 1 ` func (q *Queries) GetDevice(ctx context.Context, deviceID string) (Device, error) { row := q.db.QueryRowContext(ctx, getDevice, deviceID) var i Device err := row.Scan( &i.ID, &i.UserID, &i.DeviceName, &i.CreatedAt, &i.Sync, ) return i, err } const getDevices = `-- name: GetDevices :many SELECT id, user_id, device_name, created_at, sync FROM devices WHERE user_id = ?1 ORDER BY created_at DESC LIMIT ?3 OFFSET ?2 ` type GetDevicesParams struct { UserID string `json:"user_id"` Offset int64 `json:"offset"` Limit int64 `json:"limit"` } func (q *Queries) GetDevices(ctx context.Context, arg GetDevicesParams) ([]Device, error) { rows, err := q.db.QueryContext(ctx, getDevices, arg.UserID, arg.Offset, arg.Limit) if err != nil { return nil, err } defer rows.Close() var items []Device for rows.Next() { var i Device if err := rows.Scan( &i.ID, &i.UserID, &i.DeviceName, &i.CreatedAt, &i.Sync, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getDocument = `-- name: GetDocument :one SELECT id, md5, filepath, title, author, series, series_index, lang, description, olid, synced, deleted, updated_at, created_at FROM documents WHERE id = ?1 LIMIT 1 ` func (q *Queries) GetDocument(ctx context.Context, documentID string) (Document, error) { row := q.db.QueryRowContext(ctx, getDocument, documentID) var i Document err := row.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, ) return i, err } const getDocumentDaysRead = `-- name: GetDocumentDaysRead :one WITH document_days AS ( SELECT date(start_time, 'localtime') AS dates FROM rescaled_activity WHERE document_id = ?1 AND user_id = ?2 GROUP BY dates ) SELECT CAST(count(*) AS INTEGER) AS days_read FROM document_days ` type GetDocumentDaysReadParams struct { DocumentID string `json:"document_id"` UserID string `json:"user_id"` } func (q *Queries) GetDocumentDaysRead(ctx context.Context, arg GetDocumentDaysReadParams) (int64, error) { row := q.db.QueryRowContext(ctx, getDocumentDaysRead, arg.DocumentID, arg.UserID) var days_read int64 err := row.Scan(&days_read) return days_read, err } const getDocumentReadStats = `-- name: GetDocumentReadStats :one SELECT count(DISTINCT page) AS pages_read, sum(duration) AS total_time FROM rescaled_activity WHERE document_id = ?1 AND user_id = ?2 AND start_time >= ?3 ` type GetDocumentReadStatsParams struct { DocumentID string `json:"document_id"` UserID string `json:"user_id"` StartTime time.Time `json:"start_time"` } type GetDocumentReadStatsRow struct { PagesRead int64 `json:"pages_read"` TotalTime sql.NullFloat64 `json:"total_time"` } func (q *Queries) GetDocumentReadStats(ctx context.Context, arg GetDocumentReadStatsParams) (GetDocumentReadStatsRow, error) { row := q.db.QueryRowContext(ctx, getDocumentReadStats, arg.DocumentID, arg.UserID, arg.StartTime) var i GetDocumentReadStatsRow err := row.Scan(&i.PagesRead, &i.TotalTime) return i, err } const getDocumentReadStatsCapped = `-- name: GetDocumentReadStatsCapped :one WITH capped_stats AS ( SELECT min(sum(duration), CAST(?1 AS INTEGER)) AS durations FROM rescaled_activity WHERE document_id = ?2 AND user_id = ?3 AND start_time >= ?4 GROUP BY page ) SELECT CAST(count(*) AS INTEGER) AS pages_read, CAST(sum(durations) AS INTEGER) AS total_time FROM capped_stats ` type GetDocumentReadStatsCappedParams struct { PageDurationCap int64 `json:"page_duration_cap"` DocumentID string `json:"document_id"` UserID string `json:"user_id"` StartTime time.Time `json:"start_time"` } type GetDocumentReadStatsCappedRow struct { PagesRead int64 `json:"pages_read"` TotalTime int64 `json:"total_time"` } func (q *Queries) GetDocumentReadStatsCapped(ctx context.Context, arg GetDocumentReadStatsCappedParams) (GetDocumentReadStatsCappedRow, error) { row := q.db.QueryRowContext(ctx, getDocumentReadStatsCapped, arg.PageDurationCap, arg.DocumentID, arg.UserID, arg.StartTime, ) var i GetDocumentReadStatsCappedRow err := row.Scan(&i.PagesRead, &i.TotalTime) return i, err } const getDocuments = `-- name: GetDocuments :many SELECT id, md5, filepath, title, author, series, series_index, lang, description, olid, synced, deleted, updated_at, created_at FROM documents ORDER BY created_at DESC LIMIT ?2 OFFSET ?1 ` type GetDocumentsParams struct { Offset int64 `json:"offset"` Limit int64 `json:"limit"` } func (q *Queries) GetDocuments(ctx context.Context, arg GetDocumentsParams) ([]Document, error) { rows, err := q.db.QueryContext(ctx, getDocuments, arg.Offset, arg.Limit) if err != nil { return nil, err } defer rows.Close() var items []Document for rows.Next() { var i Document if err := rows.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getDocumentsWithStats = `-- name: GetDocumentsWithStats :many WITH true_progress AS ( SELECT start_time AS last_read, SUM(duration) / 60 AS total_time_minutes, document_id, current_page, total_pages, ROUND(CAST(current_page AS REAL) / CAST(total_pages AS REAL) * 100, 2) AS percentage FROM activity WHERE user_id = ?3 GROUP BY document_id HAVING MAX(start_time) ) SELECT documents.id, documents.md5, documents.filepath, documents.title, documents.author, documents.series, documents.series_index, documents.lang, documents.description, documents.olid, documents.synced, documents.deleted, documents.updated_at, documents.created_at, CAST(IFNULL(current_page, 0) AS INTEGER) AS current_page, CAST(IFNULL(total_pages, 0) AS INTEGER) AS total_pages, CAST(IFNULL(total_time_minutes, 0) AS INTEGER) AS total_time_minutes, CAST( STRFTIME('%Y-%m-%dT%H:%M:%SZ', IFNULL(last_read, "1970-01-01") ) AS TEXT) AS last_read, CAST(CASE WHEN percentage > 97.0 THEN 100.0 WHEN percentage IS NULL THEN 0.0 ELSE percentage END AS REAL) AS percentage FROM documents LEFT JOIN true_progress ON document_id = id ORDER BY last_read DESC, created_at DESC LIMIT ?2 OFFSET ?1 ` type GetDocumentsWithStatsParams struct { Offset int64 `json:"offset"` Limit int64 `json:"limit"` UserID string `json:"user_id"` } type GetDocumentsWithStatsRow struct { ID string `json:"id"` Md5 *string `json:"md5"` Filepath *string `json:"filepath"` Title *string `json:"title"` Author *string `json:"author"` Series *string `json:"series"` SeriesIndex *int64 `json:"series_index"` Lang *string `json:"lang"` Description *string `json:"description"` Olid *string `json:"-"` Synced bool `json:"-"` Deleted bool `json:"-"` UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"` CurrentPage int64 `json:"current_page"` TotalPages int64 `json:"total_pages"` TotalTimeMinutes int64 `json:"total_time_minutes"` LastRead string `json:"last_read"` Percentage float64 `json:"percentage"` } func (q *Queries) GetDocumentsWithStats(ctx context.Context, arg GetDocumentsWithStatsParams) ([]GetDocumentsWithStatsRow, error) { rows, err := q.db.QueryContext(ctx, getDocumentsWithStats, arg.Offset, arg.Limit, arg.UserID) if err != nil { return nil, err } defer rows.Close() var items []GetDocumentsWithStatsRow for rows.Next() { var i GetDocumentsWithStatsRow if err := rows.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, &i.CurrentPage, &i.TotalPages, &i.TotalTimeMinutes, &i.LastRead, &i.Percentage, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getLastActivity = `-- name: GetLastActivity :one SELECT start_time FROM activity WHERE device_id = ?1 AND user_id = ?2 ORDER BY start_time DESC LIMIT 1 ` type GetLastActivityParams struct { DeviceID string `json:"device_id"` UserID string `json:"user_id"` } func (q *Queries) GetLastActivity(ctx context.Context, arg GetLastActivityParams) (time.Time, error) { row := q.db.QueryRowContext(ctx, getLastActivity, arg.DeviceID, arg.UserID) var start_time time.Time err := row.Scan(&start_time) return start_time, err } const getMissingDocuments = `-- name: GetMissingDocuments :many SELECT documents.id, documents.md5, documents.filepath, documents.title, documents.author, documents.series, documents.series_index, documents.lang, documents.description, documents.olid, documents.synced, documents.deleted, documents.updated_at, documents.created_at FROM documents WHERE documents.filepath IS NOT NULL AND documents.deleted = false AND documents.id NOT IN (/*SLICE:document_ids*/?) ` func (q *Queries) GetMissingDocuments(ctx context.Context, documentIds []string) ([]Document, error) { query := getMissingDocuments var queryParams []interface{} if len(documentIds) > 0 { for _, v := range documentIds { queryParams = append(queryParams, v) } query = strings.Replace(query, "/*SLICE:document_ids*/?", strings.Repeat(",?", len(documentIds))[1:], 1) } else { query = strings.Replace(query, "/*SLICE:document_ids*/?", "NULL", 1) } rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } defer rows.Close() var items []Document for rows.Next() { var i Document if err := rows.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getProgress = `-- name: GetProgress :one SELECT document_progress.user_id, document_progress.document_id, document_progress.device_id, document_progress.percentage, document_progress.progress, document_progress.created_at, devices.device_name FROM document_progress JOIN devices ON document_progress.device_id = devices.id WHERE document_progress.user_id = ?1 AND document_progress.document_id = ?2 ORDER BY document_progress.created_at DESC LIMIT 1 ` type GetProgressParams struct { UserID string `json:"user_id"` DocumentID string `json:"document_id"` } type GetProgressRow struct { UserID string `json:"user_id"` DocumentID string `json:"document_id"` DeviceID string `json:"device_id"` Percentage float64 `json:"percentage"` Progress string `json:"progress"` CreatedAt time.Time `json:"created_at"` DeviceName string `json:"device_name"` } func (q *Queries) GetProgress(ctx context.Context, arg GetProgressParams) (GetProgressRow, error) { row := q.db.QueryRowContext(ctx, getProgress, arg.UserID, arg.DocumentID) var i GetProgressRow err := row.Scan( &i.UserID, &i.DocumentID, &i.DeviceID, &i.Percentage, &i.Progress, &i.CreatedAt, &i.DeviceName, ) return i, err } const getUser = `-- name: GetUser :one SELECT id, pass, admin, created_at FROM users WHERE id = ?1 LIMIT 1 ` func (q *Queries) GetUser(ctx context.Context, userID string) (User, error) { row := q.db.QueryRowContext(ctx, getUser, userID) var i User err := row.Scan( &i.ID, &i.Pass, &i.Admin, &i.CreatedAt, ) return i, err } const getUserDayStreaks = `-- name: GetUserDayStreaks :one WITH document_days AS ( SELECT date(start_time, 'localtime') AS read_day FROM activity WHERE user_id = ?1 GROUP BY read_day ORDER BY read_day DESC ), partitions AS ( SELECT document_days.read_day, row_number() OVER ( PARTITION BY 1 ORDER BY read_day DESC ) AS seqnum FROM document_days ), streaks AS ( SELECT count(*) AS streak, MIN(read_day) AS start_date, MAX(read_day) AS end_date FROM partitions GROUP BY date(read_day, '+' || seqnum || ' day') ORDER BY end_date DESC ), max_streak AS ( SELECT MAX(streak) AS max_streak, start_date AS max_streak_start_date, end_date AS max_streak_end_date FROM streaks ) SELECT CAST(max_streak AS INTEGER), CAST(max_streak_start_date AS TEXT), CAST(max_streak_end_date AS TEXT), streak AS current_streak, CAST(start_date AS TEXT) AS current_streak_start_date, CAST(end_date AS TEXT) AS current_streak_end_date FROM max_streak, streaks LIMIT 1 ` type GetUserDayStreaksRow struct { MaxStreak int64 `json:"max_streak"` MaxStreakStartDate string `json:"max_streak_start_date"` MaxStreakEndDate string `json:"max_streak_end_date"` CurrentStreak int64 `json:"current_streak"` CurrentStreakStartDate string `json:"current_streak_start_date"` CurrentStreakEndDate string `json:"current_streak_end_date"` } func (q *Queries) GetUserDayStreaks(ctx context.Context, userID string) (GetUserDayStreaksRow, error) { row := q.db.QueryRowContext(ctx, getUserDayStreaks, userID) var i GetUserDayStreaksRow err := row.Scan( &i.MaxStreak, &i.MaxStreakStartDate, &i.MaxStreakEndDate, &i.CurrentStreak, &i.CurrentStreakStartDate, &i.CurrentStreakEndDate, ) return i, err } const getUserWeekStreaks = `-- name: GetUserWeekStreaks :one WITH document_weeks AS ( SELECT STRFTIME('%Y-%m-%d', start_time, 'localtime', 'weekday 0', '-7 day') AS read_week FROM activity WHERE user_id = ?1 GROUP BY read_week ORDER BY read_week DESC ), partitions AS ( SELECT document_weeks.read_week, row_number() OVER ( PARTITION BY 1 ORDER BY read_week DESC ) AS seqnum FROM document_weeks ), streaks AS ( SELECT count(*) AS streak, MIN(read_week) AS start_date, MAX(read_week) AS end_date FROM partitions GROUP BY date(read_week, '+' || (seqnum * 7) || ' day') ORDER BY end_date DESC ), max_streak AS ( SELECT MAX(streak) AS max_streak, start_date AS max_streak_start_date, end_date AS max_streak_end_date FROM streaks ) SELECT CAST(max_streak AS INTEGER), CAST(max_streak_start_date AS TEXT), CAST(max_streak_end_date AS TEXT), streak AS current_streak, CAST(start_date AS TEXT) AS current_streak_start_date, CAST(end_date AS TEXT) AS current_streak_end_date FROM max_streak, streaks LIMIT 1 ` type GetUserWeekStreaksRow struct { MaxStreak int64 `json:"max_streak"` MaxStreakStartDate string `json:"max_streak_start_date"` MaxStreakEndDate string `json:"max_streak_end_date"` CurrentStreak int64 `json:"current_streak"` CurrentStreakStartDate string `json:"current_streak_start_date"` CurrentStreakEndDate string `json:"current_streak_end_date"` } func (q *Queries) GetUserWeekStreaks(ctx context.Context, userID string) (GetUserWeekStreaksRow, error) { row := q.db.QueryRowContext(ctx, getUserWeekStreaks, userID) var i GetUserWeekStreaksRow err := row.Scan( &i.MaxStreak, &i.MaxStreakStartDate, &i.MaxStreakEndDate, &i.CurrentStreak, &i.CurrentStreakStartDate, &i.CurrentStreakEndDate, ) return i, err } const getUserWindowStreaks = `-- name: GetUserWindowStreaks :one WITH document_windows AS ( SELECT CASE WHEN ?2 = "WEEK" THEN STRFTIME('%Y-%m-%d', start_time, 'localtime', 'weekday 0', '-7 day') WHEN ?2 = "DAY" THEN date(start_time, 'localtime') END AS read_window FROM activity WHERE user_id = ?1 AND CAST(?2 AS TEXT) = CAST(?2 AS TEXT) GROUP BY read_window ORDER BY read_window DESC ), partitions AS ( SELECT document_windows.read_window, row_number() OVER ( PARTITION BY 1 ORDER BY read_window DESC ) AS seqnum FROM document_windows ), streaks AS ( SELECT count(*) AS streak, MIN(read_window) AS start_date, MAX(read_window) AS end_date FROM partitions GROUP BY CASE WHEN ?2 = "DAY" THEN date(read_window, '+' || seqnum || ' day') WHEN ?2 = "WEEK" THEN date(read_window, '+' || (seqnum * 7) || ' day') END ORDER BY end_date DESC ), max_streak AS ( SELECT MAX(streak) AS max_streak, start_date AS max_streak_start_date, end_date AS max_streak_end_date FROM streaks ) SELECT CAST(max_streak AS INTEGER), CAST(max_streak_start_date AS TEXT), CAST(max_streak_end_date AS TEXT), streak AS current_streak, CAST(start_date AS TEXT) AS current_streak_start_date, CAST(end_date AS TEXT) AS current_streak_end_date FROM max_streak, streaks LIMIT 1 ` type GetUserWindowStreaksParams struct { UserID string `json:"user_id"` Window string `json:"window"` } type GetUserWindowStreaksRow struct { MaxStreak int64 `json:"max_streak"` MaxStreakStartDate string `json:"max_streak_start_date"` MaxStreakEndDate string `json:"max_streak_end_date"` CurrentStreak int64 `json:"current_streak"` CurrentStreakStartDate string `json:"current_streak_start_date"` CurrentStreakEndDate string `json:"current_streak_end_date"` } func (q *Queries) GetUserWindowStreaks(ctx context.Context, arg GetUserWindowStreaksParams) (GetUserWindowStreaksRow, error) { row := q.db.QueryRowContext(ctx, getUserWindowStreaks, arg.UserID, arg.Window) var i GetUserWindowStreaksRow err := row.Scan( &i.MaxStreak, &i.MaxStreakStartDate, &i.MaxStreakEndDate, &i.CurrentStreak, &i.CurrentStreakStartDate, &i.CurrentStreakEndDate, ) return i, err } const getUsers = `-- name: GetUsers :many SELECT id, pass, admin, created_at FROM users WHERE users.id = ?1 OR ?1 IN ( SELECT id FROM users WHERE id = ?1 AND admin = 1 ) ORDER BY created_at DESC LIMIT ?3 OFFSET ?2 ` type GetUsersParams struct { User string `json:"user"` Offset int64 `json:"offset"` Limit int64 `json:"limit"` } func (q *Queries) GetUsers(ctx context.Context, arg GetUsersParams) ([]User, error) { rows, err := q.db.QueryContext(ctx, getUsers, arg.User, arg.Offset, arg.Limit) if err != nil { return nil, err } defer rows.Close() var items []User for rows.Next() { var i User if err := rows.Scan( &i.ID, &i.Pass, &i.Admin, &i.CreatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getWantedDocuments = `-- name: GetWantedDocuments :many SELECT CAST(value AS TEXT) AS id FROM json_each(?1) LEFT JOIN documents ON value = documents.id WHERE ( documents.id IS NOT NULL AND documents.synced = false ) OR (documents.id IS NULL) OR CAST(?1 AS TEXT) != CAST(?1 AS TEXT) ` func (q *Queries) GetWantedDocuments(ctx context.Context, documentIds string) ([]string, error) { rows, err := q.db.QueryContext(ctx, getWantedDocuments, documentIds) if err != nil { return nil, err } defer rows.Close() var items []string for rows.Next() { var id string if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const updateDocumentDeleted = `-- name: UpdateDocumentDeleted :one UPDATE documents SET deleted = ?1 WHERE id = ?2 RETURNING id, md5, filepath, title, author, series, series_index, lang, description, olid, synced, deleted, updated_at, created_at ` type UpdateDocumentDeletedParams struct { Deleted bool `json:"-"` ID string `json:"id"` } func (q *Queries) UpdateDocumentDeleted(ctx context.Context, arg UpdateDocumentDeletedParams) (Document, error) { row := q.db.QueryRowContext(ctx, updateDocumentDeleted, arg.Deleted, arg.ID) var i Document err := row.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, ) return i, err } const updateDocumentSync = `-- name: UpdateDocumentSync :one UPDATE documents SET synced = ?1 WHERE id = ?2 RETURNING id, md5, filepath, title, author, series, series_index, lang, description, olid, synced, deleted, updated_at, created_at ` type UpdateDocumentSyncParams struct { Synced bool `json:"-"` ID string `json:"id"` } func (q *Queries) UpdateDocumentSync(ctx context.Context, arg UpdateDocumentSyncParams) (Document, error) { row := q.db.QueryRowContext(ctx, updateDocumentSync, arg.Synced, arg.ID) var i Document err := row.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, ) return i, err } const updateProgress = `-- name: UpdateProgress :one INSERT OR REPLACE INTO document_progress ( user_id, document_id, device_id, percentage, progress ) VALUES (?, ?, ?, ?, ?) RETURNING user_id, document_id, device_id, percentage, progress, created_at ` type UpdateProgressParams struct { UserID string `json:"user_id"` DocumentID string `json:"document_id"` DeviceID string `json:"device_id"` Percentage float64 `json:"percentage"` Progress string `json:"progress"` } func (q *Queries) UpdateProgress(ctx context.Context, arg UpdateProgressParams) (DocumentProgress, error) { row := q.db.QueryRowContext(ctx, updateProgress, arg.UserID, arg.DocumentID, arg.DeviceID, arg.Percentage, arg.Progress, ) var i DocumentProgress err := row.Scan( &i.UserID, &i.DocumentID, &i.DeviceID, &i.Percentage, &i.Progress, &i.CreatedAt, ) return i, err } const upsertDevice = `-- name: UpsertDevice :one INSERT INTO devices (id, user_id, device_name) VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET device_name = COALESCE(excluded.device_name, device_name) RETURNING id, user_id, device_name, created_at, sync ` type UpsertDeviceParams struct { ID string `json:"id"` UserID string `json:"user_id"` DeviceName string `json:"device_name"` } func (q *Queries) UpsertDevice(ctx context.Context, arg UpsertDeviceParams) (Device, error) { row := q.db.QueryRowContext(ctx, upsertDevice, arg.ID, arg.UserID, arg.DeviceName) var i Device err := row.Scan( &i.ID, &i.UserID, &i.DeviceName, &i.CreatedAt, &i.Sync, ) return i, err } const upsertDocument = `-- name: UpsertDocument :one INSERT INTO documents ( id, md5, filepath, title, author, series, series_index, lang, description, olid ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO UPDATE SET md5 = COALESCE(excluded.md5, md5), filepath = COALESCE(excluded.filepath, filepath), title = COALESCE(excluded.title, title), author = COALESCE(excluded.author, author), series = COALESCE(excluded.series, series), series_index = COALESCE(excluded.series_index, series_index), lang = COALESCE(excluded.lang, lang), description = COALESCE(excluded.description, description), olid = COALESCE(excluded.olid, olid) RETURNING id, md5, filepath, title, author, series, series_index, lang, description, olid, synced, deleted, updated_at, created_at ` type UpsertDocumentParams struct { ID string `json:"id"` Md5 *string `json:"md5"` Filepath *string `json:"filepath"` Title *string `json:"title"` Author *string `json:"author"` Series *string `json:"series"` SeriesIndex *int64 `json:"series_index"` Lang *string `json:"lang"` Description *string `json:"description"` Olid *string `json:"-"` } func (q *Queries) UpsertDocument(ctx context.Context, arg UpsertDocumentParams) (Document, error) { row := q.db.QueryRowContext(ctx, upsertDocument, arg.ID, arg.Md5, arg.Filepath, arg.Title, arg.Author, arg.Series, arg.SeriesIndex, arg.Lang, arg.Description, arg.Olid, ) var i Document err := row.Scan( &i.ID, &i.Md5, &i.Filepath, &i.Title, &i.Author, &i.Series, &i.SeriesIndex, &i.Lang, &i.Description, &i.Olid, &i.Synced, &i.Deleted, &i.UpdatedAt, &i.CreatedAt, ) return i, err }