updated deps; updated healthchecks.io integration
This commit is contained in:
13
vendor/go.mau.fi/util/dbutil/json.go
vendored
13
vendor/go.mau.fi/util/dbutil/json.go
vendored
@@ -31,3 +31,16 @@ func (j JSON) Value() (driver.Value, error) {
|
||||
v, err := json.Marshal(j.Data)
|
||||
return string(v), err
|
||||
}
|
||||
|
||||
// JSONPtr is a convenience function for wrapping a pointer to a value in the JSON utility, but removing typed nils
|
||||
// (i.e. preventing nils from turning into the string "null" in the database).
|
||||
func JSONPtr[T any](val *T) JSON {
|
||||
return JSON{Data: UntypedNil(val)}
|
||||
}
|
||||
|
||||
func UntypedNil[T any](val *T) any {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
29
vendor/go.mau.fi/util/dbutil/queryhelper.go
vendored
29
vendor/go.mau.fi/util/dbutil/queryhelper.go
vendored
@@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
@@ -60,6 +61,34 @@ func NumPtr[T constraints.Integer | constraints.Float](val T) *T {
|
||||
return &val
|
||||
}
|
||||
|
||||
// UnixPtr returns a pointer to the given time as unix seconds, or nil if the time is zero.
|
||||
func UnixPtr(val time.Time) *int64 {
|
||||
return ConvertedPtr(val, time.Time.Unix)
|
||||
}
|
||||
|
||||
// UnixMilliPtr returns a pointer to the given time as unix milliseconds, or nil if the time is zero.
|
||||
func UnixMilliPtr(val time.Time) *int64 {
|
||||
return ConvertedPtr(val, time.Time.UnixMilli)
|
||||
}
|
||||
|
||||
type Zeroable interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
// ConvertedPtr returns a pointer to the converted version of the given value, or nil if the input is zero.
|
||||
//
|
||||
// This is primarily meant for time.Time, but it can be used with any type that has implements `IsZero() bool`.
|
||||
//
|
||||
// yourTime := time.Now()
|
||||
// unixMSPtr := dbutil.TimePtr(yourTime, time.Time.UnixMilli)
|
||||
func ConvertedPtr[Input Zeroable, Output any](val Input, converter func(Input) Output) *Output {
|
||||
if val.IsZero() {
|
||||
return nil
|
||||
}
|
||||
converted := converter(val)
|
||||
return &converted
|
||||
}
|
||||
|
||||
func (qh *QueryHelper[T]) GetDB() *Database {
|
||||
return qh.db
|
||||
}
|
||||
|
||||
45
vendor/go.mau.fi/util/dbutil/transaction.go
vendored
45
vendor/go.mau.fi/util/dbutil/transaction.go
vendored
@@ -11,6 +11,7 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
@@ -45,27 +46,55 @@ func (db *Database) QueryRow(ctx context.Context, query string, args ...any) *sq
|
||||
}
|
||||
|
||||
func (db *Database) BeginTx(ctx context.Context, opts *sql.TxOptions) (*LoggingTxn, error) {
|
||||
if ctx == nil {
|
||||
panic("BeginTx() called with nil ctx")
|
||||
}
|
||||
return db.LoggingDB.BeginTx(ctx, opts)
|
||||
}
|
||||
|
||||
func (db *Database) DoTxn(ctx context.Context, opts *sql.TxOptions, fn func(ctx context.Context) error) error {
|
||||
if ctx == nil {
|
||||
panic("DoTxn() called with nil ctx")
|
||||
}
|
||||
if ctx.Value(ContextKeyDatabaseTransaction) != nil {
|
||||
zerolog.Ctx(ctx).Trace().Msg("Already in a transaction, not creating a new one")
|
||||
return fn(ctx)
|
||||
}
|
||||
|
||||
log := zerolog.Ctx(ctx).With().Str("db_txn_id", random.String(12)).Logger()
|
||||
slowLog := log
|
||||
|
||||
callerSkip := 1
|
||||
if val := ctx.Value(ContextKeyDoTxnCallerSkip); val != nil {
|
||||
callerSkip += val.(int)
|
||||
}
|
||||
if pc, file, line, ok := runtime.Caller(callerSkip); ok {
|
||||
slowLog = log.With().Str(zerolog.CallerFieldName, zerolog.CallerMarshalFunc(pc, file, line)).Logger()
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
deadlockCh := make(chan struct{})
|
||||
go func() {
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
slowLog.Warn().
|
||||
Dur("duration_seconds", time.Since(start)).
|
||||
Msg("Transaction still running")
|
||||
case <-deadlockCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
close(deadlockCh)
|
||||
dur := time.Since(start)
|
||||
if dur > time.Second {
|
||||
val := ctx.Value(ContextKeyDoTxnCallerSkip)
|
||||
callerSkip := 2
|
||||
if val != nil {
|
||||
callerSkip += val.(int)
|
||||
}
|
||||
log.Warn().
|
||||
slowLog.Warn().
|
||||
Float64("duration_seconds", dur.Seconds()).
|
||||
Caller(callerSkip).
|
||||
Msg("Transaction took long")
|
||||
}
|
||||
}()
|
||||
@@ -100,7 +129,7 @@ func (db *Database) DoTxn(ctx context.Context, opts *sql.TxOptions, fn func(ctx
|
||||
|
||||
func (db *Database) Conn(ctx context.Context) Execable {
|
||||
if ctx == nil {
|
||||
return &db.LoggingDB
|
||||
panic("Conn() called with nil ctx")
|
||||
}
|
||||
txn, ok := ctx.Value(ContextKeyDatabaseTransaction).(Transaction)
|
||||
if ok {
|
||||
|
||||
30
vendor/go.mau.fi/util/jsonbytes/unpadded.go
vendored
Normal file
30
vendor/go.mau.fi/util/jsonbytes/unpadded.go
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2024 Sumner Evans
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package jsonbytes
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// UnpaddedBytes is a byte slice that is encoded and decoded using
|
||||
// [base64.RawStdEncoding] instead of the default padded base64.
|
||||
type UnpaddedBytes []byte
|
||||
|
||||
func (b UnpaddedBytes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(base64.RawStdEncoding.EncodeToString(b))
|
||||
}
|
||||
|
||||
func (b *UnpaddedBytes) UnmarshalJSON(data []byte) error {
|
||||
var b64str string
|
||||
err := json.Unmarshal(data, &b64str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*b, err = base64.RawStdEncoding.DecodeString(b64str)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user