mirror of
https://github.com/ddworken/hishtory.git
synced 2025-06-25 06:22:24 +02:00
Rename a bunch of DB functions + add error checking for DB table creation (follow up to #104)
This commit is contained in:
parent
ea10050872
commit
50c74e5881
@ -60,7 +60,7 @@ func updateUsageData(r *http.Request, userId, deviceId string, numEntriesHandled
|
||||
return fmt.Errorf("db.UsageDataFindByUserAndDevice: %w", err)
|
||||
}
|
||||
if len(usageData) == 0 {
|
||||
err := GLOBAL_DB.UsageDataCreate(
|
||||
err := GLOBAL_DB.CreateUsageData(
|
||||
r.Context(),
|
||||
&shared.UsageData{
|
||||
UserId: userId,
|
||||
@ -71,28 +71,28 @@ func updateUsageData(r *http.Request, userId, deviceId string, numEntriesHandled
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db.UsageDataCreate: %w", err)
|
||||
return fmt.Errorf("db.CreateUsageData: %w", err)
|
||||
}
|
||||
} else {
|
||||
usage := usageData[0]
|
||||
|
||||
if err := GLOBAL_DB.UsageDataUpdate(r.Context(), userId, deviceId, time.Now(), getRemoteAddr(r)); err != nil {
|
||||
return fmt.Errorf("db.UsageDataUpdate: %w", err)
|
||||
if err := GLOBAL_DB.UpdateUsageData(r.Context(), userId, deviceId, time.Now(), getRemoteAddr(r)); err != nil {
|
||||
return fmt.Errorf("db.UpdateUsageData: %w", err)
|
||||
}
|
||||
if numEntriesHandled > 0 {
|
||||
if err := GLOBAL_DB.UsageDataUpdateNumEntriesHandled(r.Context(), userId, deviceId, numEntriesHandled); err != nil {
|
||||
return fmt.Errorf("db.UsageDataUpdateNumEntriesHandled: %w", err)
|
||||
if err := GLOBAL_DB.UpdateUsageDataForNumEntriesHandled(r.Context(), userId, deviceId, numEntriesHandled); err != nil {
|
||||
return fmt.Errorf("db.UpdateUsageDataForNumEntriesHandled: %w", err)
|
||||
}
|
||||
}
|
||||
if usage.Version != getHishtoryVersion(r) {
|
||||
if err := GLOBAL_DB.UsageDataUpdateVersion(r.Context(), userId, deviceId, getHishtoryVersion(r)); err != nil {
|
||||
return fmt.Errorf("db.UsageDataUpdateVersion: %w", err)
|
||||
if err := GLOBAL_DB.UpdateUsageDataClientVersion(r.Context(), userId, deviceId, getHishtoryVersion(r)); err != nil {
|
||||
return fmt.Errorf("db.UpdateUsageDataClientVersion: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if isQuery {
|
||||
if err := GLOBAL_DB.UsageDataUpdateNumQueries(r.Context(), userId, deviceId); err != nil {
|
||||
return fmt.Errorf("db.UsageDataUpdateNumQueries: %w", err)
|
||||
if err := GLOBAL_DB.UpdateUsageDataNumberQueries(r.Context(), userId, deviceId); err != nil {
|
||||
return fmt.Errorf("db.UpdateUsageDataNumberQueries: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,23 +125,23 @@ func usageStatsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func statsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
numDevices, err := GLOBAL_DB.DevicesCount(r.Context())
|
||||
numDevices, err := GLOBAL_DB.CountAllDevices(r.Context())
|
||||
checkGormError(err, 0)
|
||||
|
||||
numEntriesProcessed, err := GLOBAL_DB.UsageDataTotal(r.Context())
|
||||
checkGormError(err, 0)
|
||||
|
||||
numDbEntries, err := GLOBAL_DB.EncHistoryEntryCount(r.Context())
|
||||
numDbEntries, err := GLOBAL_DB.CountHistoryEntries(r.Context())
|
||||
checkGormError(err, 0)
|
||||
|
||||
oneWeek := time.Hour * 24 * 7
|
||||
weeklyActiveInstalls, err := GLOBAL_DB.WeeklyActiveInstalls(r.Context(), oneWeek)
|
||||
weeklyActiveInstalls, err := GLOBAL_DB.CountActiveInstalls(r.Context(), oneWeek)
|
||||
checkGormError(err, 0)
|
||||
|
||||
weeklyQueryUsers, err := GLOBAL_DB.WeeklyQueryUsers(r.Context(), oneWeek)
|
||||
weeklyQueryUsers, err := GLOBAL_DB.CountQueryUsers(r.Context(), oneWeek)
|
||||
checkGormError(err, 0)
|
||||
|
||||
lastRegistration, err := GLOBAL_DB.LastRegistration(r.Context())
|
||||
lastRegistration, err := GLOBAL_DB.DateOfLastRegistration(r.Context())
|
||||
checkGormError(err, 0)
|
||||
|
||||
_, _ = fmt.Fprintf(w, "Num devices: %d\n", numDevices)
|
||||
@ -166,9 +166,7 @@ func apiSubmitHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if len(entries) == 0 {
|
||||
return
|
||||
}
|
||||
if err := updateUsageData(r, entries[0].UserId, entries[0].DeviceId, len(entries), false); err != nil {
|
||||
fmt.Printf("updateUsageData: %v\n", err)
|
||||
}
|
||||
_ = updateUsageData(r, entries[0].UserId, entries[0].DeviceId /* numEntriesHandled = */, len(entries) /* isQuery = */, false)
|
||||
|
||||
devices, err := GLOBAL_DB.DevicesForUser(r.Context(), entries[0].UserId)
|
||||
checkGormError(err, 0)
|
||||
@ -178,7 +176,7 @@ func apiSubmitHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
fmt.Printf("apiSubmitHandler: Found %d devices\n", len(devices))
|
||||
|
||||
err = GLOBAL_DB.DeviceEntriesCreateChunk(r.Context(), devices, entries, 1000)
|
||||
err = GLOBAL_DB.AddHistoryEntriesForAllDevices(r.Context(), devices, entries)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to execute transaction to add entries to DB: %w", err))
|
||||
}
|
||||
@ -193,8 +191,8 @@ func apiSubmitHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func apiBootstrapHandler(w http.ResponseWriter, r *http.Request) {
|
||||
userId := getRequiredQueryParam(r, "user_id")
|
||||
deviceId := getRequiredQueryParam(r, "device_id")
|
||||
updateUsageData(r, userId, deviceId, 0, false)
|
||||
historyEntries, err := GLOBAL_DB.EncHistoryEntriesForUser(r.Context(), userId)
|
||||
_ = updateUsageData(r, userId, deviceId /* numEntriesHandled = */, 0 /* isQuery = */, false)
|
||||
historyEntries, err := GLOBAL_DB.AllHistoryEntriesForUser(r.Context(), userId)
|
||||
checkGormError(err, 1)
|
||||
fmt.Printf("apiBootstrapHandler: Found %d entries\n", len(historyEntries))
|
||||
if err := json.NewEncoder(w).Encode(historyEntries); err != nil {
|
||||
@ -206,7 +204,7 @@ func apiQueryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
userId := getRequiredQueryParam(r, "user_id")
|
||||
deviceId := getRequiredQueryParam(r, "device_id")
|
||||
updateUsageData(r, userId, deviceId, 0, true)
|
||||
_ = updateUsageData(r, userId, deviceId /* numEntriesHandled = */, 0 /* isQuery = */, true)
|
||||
|
||||
// Delete any entries that match a pending deletion request
|
||||
deletionRequests, err := GLOBAL_DB.DeletionRequestsForUserAndDevice(r.Context(), userId, deviceId)
|
||||
@ -217,7 +215,7 @@ func apiQueryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Then retrieve
|
||||
historyEntries, err := GLOBAL_DB.EncHistoryEntriesForDevice(r.Context(), deviceId, 5)
|
||||
historyEntries, err := GLOBAL_DB.HistoryEntriesForDevice(r.Context(), deviceId, 5)
|
||||
checkGormError(err, 0)
|
||||
fmt.Printf("apiQueryHandler: Found %d entries for %s\n", len(historyEntries), r.URL)
|
||||
if err := json.NewEncoder(w).Encode(historyEntries); err != nil {
|
||||
@ -229,11 +227,11 @@ func apiQueryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if isProductionEnvironment() {
|
||||
go func() {
|
||||
span, ctx := tracer.StartSpanFromContext(ctx, "apiQueryHandler.incrementReadCount")
|
||||
err := GLOBAL_DB.DeviceIncrementReadCounts(ctx, deviceId)
|
||||
err := GLOBAL_DB.IncrementEntryReadCountsForDevice(ctx, deviceId)
|
||||
span.Finish(tracer.WithError(err))
|
||||
}()
|
||||
} else {
|
||||
err := GLOBAL_DB.DeviceIncrementReadCounts(ctx, deviceId)
|
||||
err := GLOBAL_DB.IncrementEntryReadCountsForDevice(ctx, deviceId)
|
||||
if err != nil {
|
||||
panic("failed to increment read counts")
|
||||
}
|
||||
@ -265,10 +263,10 @@ func apiRegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
userId := getRequiredQueryParam(r, "user_id")
|
||||
deviceId := getRequiredQueryParam(r, "device_id")
|
||||
|
||||
existingDevicesCount, err := GLOBAL_DB.DevicesCountForUser(r.Context(), userId)
|
||||
existingDevicesCount, err := GLOBAL_DB.CountDevicesForUser(r.Context(), userId)
|
||||
checkGormError(err, 0)
|
||||
fmt.Printf("apiRegisterHandler: existingDevicesCount=%d\n", existingDevicesCount)
|
||||
if err := GLOBAL_DB.DeviceCreate(r.Context(), &shared.Device{UserId: userId, DeviceId: deviceId, RegistrationIp: getRemoteAddr(r), RegistrationDate: time.Now()}); err != nil {
|
||||
if err := GLOBAL_DB.CreateDevice(r.Context(), &shared.Device{UserId: userId, DeviceId: deviceId, RegistrationIp: getRemoteAddr(r), RegistrationDate: time.Now()}); err != nil {
|
||||
checkGormError(err, 0)
|
||||
}
|
||||
|
||||
@ -276,9 +274,7 @@ func apiRegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err := GLOBAL_DB.DumpRequestCreate(r.Context(), &shared.DumpRequest{UserId: userId, RequestingDeviceId: deviceId, RequestTime: time.Now()})
|
||||
checkGormError(err, 0)
|
||||
}
|
||||
if err := updateUsageData(r, userId, deviceId, 0, false); err != nil {
|
||||
fmt.Printf("updateUsageData: %v\n", err)
|
||||
}
|
||||
_ = updateUsageData(r, userId, deviceId /* numEntriesHandled = */, 0 /* isQuery = */, false)
|
||||
|
||||
if GLOBAL_STATSD != nil {
|
||||
GLOBAL_STATSD.Incr("hishtory.register", []string{}, 1.0)
|
||||
@ -324,11 +320,11 @@ func apiSubmitDumpHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
err = GLOBAL_DB.EncHistoryCreateMulti(r.Context(), entries...)
|
||||
err = GLOBAL_DB.AddHistoryEntries(r.Context(), entries...)
|
||||
checkGormError(err, 0)
|
||||
err = GLOBAL_DB.DumpRequestDeleteForUserAndDevice(r.Context(), userId, requestingDeviceId)
|
||||
checkGormError(err, 0)
|
||||
updateUsageData(r, userId, srcDeviceId, len(entries), false)
|
||||
_ = updateUsageData(r, userId, srcDeviceId /* numEntriesHandled = */, len(entries) /* isQuery = */, false)
|
||||
|
||||
w.Header().Set("Content-Length", "0")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@ -384,28 +380,19 @@ func addDeletionRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if isProductionEnvironment() {
|
||||
// Check that we have a reasonable looking set of devices/entries in the DB
|
||||
//rows, err := GLOBAL_DB.Raw("SELECT true FROM enc_history_entries LIMIT 1 OFFSET 1000").Rows()
|
||||
//if err != nil {
|
||||
// panic(fmt.Sprintf("failed to count entries in DB: %v", err))
|
||||
//}
|
||||
//defer rows.Close()
|
||||
//if !rows.Next() {
|
||||
// panic("Suspiciously few enc history entries!")
|
||||
//}
|
||||
encHistoryEntryCount, err := GLOBAL_DB.EncHistoryEntryCount(r.Context())
|
||||
encHistoryEntryCount, err := GLOBAL_DB.CountHistoryEntries(r.Context())
|
||||
checkGormError(err, 0)
|
||||
if encHistoryEntryCount < 1000 {
|
||||
panic("Suspiciously few enc history entries!")
|
||||
}
|
||||
|
||||
deviceCount, err := GLOBAL_DB.DevicesCount(r.Context())
|
||||
deviceCount, err := GLOBAL_DB.CountAllDevices(r.Context())
|
||||
checkGormError(err, 0)
|
||||
if deviceCount < 100 {
|
||||
panic("Suspiciously few devices!")
|
||||
}
|
||||
// Check that we can write to the DB. This entry will get written and then eventually cleaned by the cron.
|
||||
err = GLOBAL_DB.EncHistoryCreate(r.Context(), &shared.EncHistoryEntry{
|
||||
err = GLOBAL_DB.AddHistoryEntries(r.Context(), &shared.EncHistoryEntry{
|
||||
EncryptedData: []byte("data"),
|
||||
Nonce: []byte("nonce"),
|
||||
DeviceId: "healthcheck_device_id",
|
||||
@ -432,7 +419,7 @@ func wipeDbEntriesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
panic("refusing to wipe the DB non-test environment")
|
||||
}
|
||||
|
||||
err := GLOBAL_DB.EncHistoryClear(r.Context())
|
||||
err := GLOBAL_DB.Unsafe_DeleteAllHistoryEntries(r.Context())
|
||||
checkGormError(err, 0)
|
||||
|
||||
w.Header().Set("Content-Length", "0")
|
||||
@ -468,7 +455,10 @@ func OpenDB() (*database.DB, error) {
|
||||
}
|
||||
underlyingDb.SetMaxOpenConns(1)
|
||||
db.Exec("PRAGMA journal_mode = WAL")
|
||||
db.AddDatabaseTables()
|
||||
err = db.AddDatabaseTables()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create underlying DB tables: %w", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@ -506,7 +496,10 @@ func OpenDB() (*database.DB, error) {
|
||||
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
|
||||
}
|
||||
}
|
||||
db.AddDatabaseTables()
|
||||
err := db.AddDatabaseTables()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create underlying DB tables: %w", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@ -901,3 +894,4 @@ func getMaximumNumberOfAllowedUsers() int {
|
||||
}
|
||||
|
||||
// TODO(optimization): Maybe optimize the endpoints a bit to reduce the number of round trips required?
|
||||
// TODO: Add error checking for the calls to updateUsageData(...) that logs it/triggers an alert in prod, but is an error in test
|
||||
|
@ -3,21 +3,11 @@ package database
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ddworken/hishtory/shared"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (db *DB) DevicesCountForUser(ctx context.Context, userID string) (int64, error) {
|
||||
var existingDevicesCount int64
|
||||
tx := db.WithContext(ctx).Model(&shared.Device{}).Where("user_id = ?", userID).Count(&existingDevicesCount)
|
||||
if tx.Error != nil {
|
||||
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return existingDevicesCount, nil
|
||||
}
|
||||
|
||||
func (db *DB) DevicesCount(ctx context.Context) (int64, error) {
|
||||
func (db *DB) CountAllDevices(ctx context.Context) (int64, error) {
|
||||
var numDevices int64 = 0
|
||||
tx := db.WithContext(ctx).Model(&shared.Device{}).Count(&numDevices)
|
||||
if tx.Error != nil {
|
||||
@ -27,7 +17,17 @@ func (db *DB) DevicesCount(ctx context.Context) (int64, error) {
|
||||
return numDevices, nil
|
||||
}
|
||||
|
||||
func (db *DB) DeviceCreate(ctx context.Context, device *shared.Device) error {
|
||||
func (db *DB) CountDevicesForUser(ctx context.Context, userID string) (int64, error) {
|
||||
var existingDevicesCount int64
|
||||
tx := db.WithContext(ctx).Model(&shared.Device{}).Where("user_id = ?", userID).Count(&existingDevicesCount)
|
||||
if tx.Error != nil {
|
||||
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return existingDevicesCount, nil
|
||||
}
|
||||
|
||||
func (db *DB) CreateDevice(ctx context.Context, device *shared.Device) error {
|
||||
tx := db.WithContext(ctx).Create(device)
|
||||
if tx.Error != nil {
|
||||
return fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
@ -36,24 +36,6 @@ func (db *DB) DeviceCreate(ctx context.Context, device *shared.Device) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) DeviceEntriesCreateChunk(ctx context.Context, devices []*shared.Device, entries []*shared.EncHistoryEntry, chunkSize int) error {
|
||||
return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
for _, device := range devices {
|
||||
for _, entry := range entries {
|
||||
entry.DeviceId = device.DeviceId
|
||||
}
|
||||
// Chunk the inserts to prevent the `extended protocol limited to 65535 parameters` error
|
||||
for _, entriesChunk := range shared.Chunks(entries, chunkSize) {
|
||||
resp := tx.Create(&entriesChunk)
|
||||
if resp.Error != nil {
|
||||
return fmt.Errorf("resp.Error: %w", resp.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (db *DB) DevicesForUser(ctx context.Context, userID string) ([]*shared.Device, error) {
|
||||
var devices []*shared.Device
|
||||
tx := db.WithContext(ctx).Where("user_id = ?", userID).Find(&devices)
|
||||
@ -63,7 +45,3 @@ func (db *DB) DevicesForUser(ctx context.Context, userID string) ([]*shared.Devi
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
func (db *DB) DeviceIncrementReadCounts(ctx context.Context, deviceID string) error {
|
||||
return db.WithContext(ctx).Exec("UPDATE enc_history_entries SET read_count = read_count + 1 WHERE device_id = ?", deviceID).Error
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ddworken/hishtory/shared"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (db *DB) EncHistoryEntryCount(ctx context.Context) (int64, error) {
|
||||
var numDbEntries int64
|
||||
tx := db.WithContext(ctx).Model(&shared.EncHistoryEntry{}).Count(&numDbEntries)
|
||||
if tx.Error != nil {
|
||||
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return numDbEntries, nil
|
||||
}
|
||||
|
||||
func (db *DB) EncHistoryEntriesForUser(ctx context.Context, userID string) ([]*shared.EncHistoryEntry, error) {
|
||||
var historyEntries []*shared.EncHistoryEntry
|
||||
tx := db.WithContext(ctx).Where("user_id = ?", userID).Find(&historyEntries)
|
||||
|
||||
if tx.Error != nil {
|
||||
return nil, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return historyEntries, nil
|
||||
}
|
||||
|
||||
func (db *DB) EncHistoryEntriesForDevice(ctx context.Context, deviceID string, limit int) ([]*shared.EncHistoryEntry, error) {
|
||||
var historyEntries []*shared.EncHistoryEntry
|
||||
tx := db.WithContext(ctx).Where("device_id = ? AND read_count < ?", deviceID, limit).Find(&historyEntries)
|
||||
|
||||
if tx.Error != nil {
|
||||
return nil, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return historyEntries, nil
|
||||
}
|
||||
|
||||
func (db *DB) EncHistoryCreate(ctx context.Context, entry *shared.EncHistoryEntry) error {
|
||||
tx := db.WithContext(ctx).Create(entry)
|
||||
if tx.Error != nil {
|
||||
return fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) EncHistoryCreateMulti(ctx context.Context, entries ...*shared.EncHistoryEntry) error {
|
||||
return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
for _, entry := range entries {
|
||||
resp := tx.Create(&entry)
|
||||
if resp.Error != nil {
|
||||
return fmt.Errorf("resp.Error: %w", resp.Error)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (db *DB) EncHistoryClear(ctx context.Context) error {
|
||||
tx := db.WithContext(ctx).Exec("DELETE FROM enc_history_entries")
|
||||
if tx.Error != nil {
|
||||
return fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
85
internal/database/historyentries.go
Normal file
85
internal/database/historyentries.go
Normal file
@ -0,0 +1,85 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ddworken/hishtory/shared"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (db *DB) CountHistoryEntries(ctx context.Context) (int64, error) {
|
||||
var numDbEntries int64
|
||||
tx := db.WithContext(ctx).Model(&shared.EncHistoryEntry{}).Count(&numDbEntries)
|
||||
if tx.Error != nil {
|
||||
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return numDbEntries, nil
|
||||
}
|
||||
|
||||
func (db *DB) AllHistoryEntriesForUser(ctx context.Context, userID string) ([]*shared.EncHistoryEntry, error) {
|
||||
var historyEntries []*shared.EncHistoryEntry
|
||||
tx := db.WithContext(ctx).Where("user_id = ?", userID).Find(&historyEntries)
|
||||
|
||||
if tx.Error != nil {
|
||||
return nil, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return historyEntries, nil
|
||||
}
|
||||
|
||||
func (db *DB) HistoryEntriesForDevice(ctx context.Context, deviceID string, limit int) ([]*shared.EncHistoryEntry, error) {
|
||||
var historyEntries []*shared.EncHistoryEntry
|
||||
tx := db.WithContext(ctx).Where("device_id = ? AND read_count < ?", deviceID, limit).Find(&historyEntries)
|
||||
|
||||
if tx.Error != nil {
|
||||
return nil, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return historyEntries, nil
|
||||
}
|
||||
|
||||
func (db *DB) AddHistoryEntries(ctx context.Context, entries ...*shared.EncHistoryEntry) error {
|
||||
return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
for _, entry := range entries {
|
||||
resp := tx.Create(&entry)
|
||||
if resp.Error != nil {
|
||||
return fmt.Errorf("resp.Error: %w", resp.Error)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (db *DB) AddHistoryEntriesForAllDevices(ctx context.Context, devices []*shared.Device, entries []*shared.EncHistoryEntry) error {
|
||||
chunkSize := 1000
|
||||
return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
for _, device := range devices {
|
||||
for _, entry := range entries {
|
||||
entry.DeviceId = device.DeviceId
|
||||
}
|
||||
// Chunk the inserts to prevent the `extended protocol limited to 65535 parameters` error
|
||||
for _, entriesChunk := range shared.Chunks(entries, chunkSize) {
|
||||
resp := tx.Create(&entriesChunk)
|
||||
if resp.Error != nil {
|
||||
return fmt.Errorf("resp.Error: %w", resp.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (db *DB) Unsafe_DeleteAllHistoryEntries(ctx context.Context) error {
|
||||
tx := db.WithContext(ctx).Exec("DELETE FROM enc_history_entries")
|
||||
if tx.Error != nil {
|
||||
return fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) IncrementEntryReadCountsForDevice(ctx context.Context, deviceID string) error {
|
||||
return db.WithContext(ctx).Exec("UPDATE enc_history_entries SET read_count = read_count + 1 WHERE device_id = ?", deviceID).Error
|
||||
}
|
@ -3,8 +3,9 @@ package database
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ddworken/hishtory/shared"
|
||||
"time"
|
||||
|
||||
"github.com/ddworken/hishtory/shared"
|
||||
)
|
||||
|
||||
func (db *DB) UsageDataFindByUserAndDevice(ctx context.Context, userId, deviceId string) ([]shared.UsageData, error) {
|
||||
@ -22,7 +23,7 @@ func (db *DB) UsageDataFindByUserAndDevice(ctx context.Context, userId, deviceId
|
||||
return usageData, nil
|
||||
}
|
||||
|
||||
func (db *DB) UsageDataCreate(ctx context.Context, usageData *shared.UsageData) error {
|
||||
func (db *DB) CreateUsageData(ctx context.Context, usageData *shared.UsageData) error {
|
||||
tx := db.DB.WithContext(ctx).Create(usageData)
|
||||
if tx.Error != nil {
|
||||
return fmt.Errorf("db.WithContext.Create: %w", tx.Error)
|
||||
@ -31,8 +32,8 @@ func (db *DB) UsageDataCreate(ctx context.Context, usageData *shared.UsageData)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UsageDataUpdate updates the entry for a given userID/deviceID pair with the lastUsed and lastIP values
|
||||
func (db *DB) UsageDataUpdate(ctx context.Context, userId, deviceId string, lastUsed time.Time, lastIP string) error {
|
||||
// UpdateUsageData updates the entry for a given userID/deviceID pair with the lastUsed and lastIP values
|
||||
func (db *DB) UpdateUsageData(ctx context.Context, userId, deviceId string, lastUsed time.Time, lastIP string) error {
|
||||
tx := db.DB.WithContext(ctx).Model(&shared.UsageData{}).
|
||||
Where("user_id = ? AND device_id = ?", userId, deviceId).
|
||||
Update("last_used", lastUsed).
|
||||
@ -45,7 +46,7 @@ func (db *DB) UsageDataUpdate(ctx context.Context, userId, deviceId string, last
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) UsageDataUpdateNumEntriesHandled(ctx context.Context, userId, deviceId string, numEntriesHandled int) error {
|
||||
func (db *DB) UpdateUsageDataForNumEntriesHandled(ctx context.Context, userId, deviceId string, numEntriesHandled int) error {
|
||||
tx := db.DB.WithContext(ctx).Exec("UPDATE usage_data SET num_entries_handled = COALESCE(num_entries_handled, 0) + ? WHERE user_id = ? AND device_id = ?", numEntriesHandled, userId, deviceId)
|
||||
|
||||
if tx.Error != nil {
|
||||
@ -55,7 +56,7 @@ func (db *DB) UsageDataUpdateNumEntriesHandled(ctx context.Context, userId, devi
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) UsageDataUpdateVersion(ctx context.Context, userID, deviceID string, version string) error {
|
||||
func (db *DB) UpdateUsageDataClientVersion(ctx context.Context, userID, deviceID string, version string) error {
|
||||
tx := db.DB.WithContext(ctx).Exec("UPDATE usage_data SET version = ? WHERE user_id = ? AND device_id = ?", version, userID, deviceID)
|
||||
|
||||
if tx.Error != nil {
|
||||
@ -65,7 +66,7 @@ func (db *DB) UsageDataUpdateVersion(ctx context.Context, userID, deviceID strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) UsageDataUpdateNumQueries(ctx context.Context, userID, deviceID string) error {
|
||||
func (db *DB) UpdateUsageDataNumberQueries(ctx context.Context, userID, deviceID string) error {
|
||||
tx := db.DB.WithContext(ctx).Exec("UPDATE usage_data SET num_queries = COALESCE(num_queries, 0) + 1, last_queried = ? WHERE user_id = ? AND device_id = ?", time.Now(), userID, deviceID)
|
||||
|
||||
if tx.Error != nil {
|
||||
@ -148,27 +149,27 @@ func (db *DB) UsageDataTotal(ctx context.Context) (int64, error) {
|
||||
return int64(nep.Total), nil
|
||||
}
|
||||
|
||||
func (db *DB) WeeklyActiveInstalls(ctx context.Context, since time.Duration) (int64, error) {
|
||||
var weeklyActiveInstalls int64
|
||||
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Where("last_used > ?", time.Now().Add(-since)).Count(&weeklyActiveInstalls)
|
||||
func (db *DB) CountActiveInstalls(ctx context.Context, since time.Duration) (int64, error) {
|
||||
var activeInstalls int64
|
||||
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Where("last_used > ?", time.Now().Add(-since)).Count(&activeInstalls)
|
||||
if tx.Error != nil {
|
||||
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return weeklyActiveInstalls, nil
|
||||
return activeInstalls, nil
|
||||
}
|
||||
|
||||
func (db *DB) WeeklyQueryUsers(ctx context.Context, since time.Duration) (int64, error) {
|
||||
var weeklyQueryUsers int64
|
||||
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Where("last_queried > ?", time.Now().Add(-since)).Count(&weeklyQueryUsers)
|
||||
func (db *DB) CountQueryUsers(ctx context.Context, since time.Duration) (int64, error) {
|
||||
var activeQueryUsers int64
|
||||
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Where("last_queried > ?", time.Now().Add(-since)).Count(&activeQueryUsers)
|
||||
if tx.Error != nil {
|
||||
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
|
||||
}
|
||||
|
||||
return weeklyQueryUsers, nil
|
||||
return activeQueryUsers, nil
|
||||
}
|
||||
|
||||
func (db *DB) LastRegistration(ctx context.Context) (string, error) {
|
||||
func (db *DB) DateOfLastRegistration(ctx context.Context) (string, error) {
|
||||
var lastRegistration string
|
||||
row := db.WithContext(ctx).Raw("SELECT to_char(max(registration_date), 'DD Month YYYY HH24:MI') FROM devices").Row()
|
||||
if err := row.Scan(&lastRegistration); err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user