Compare commits

..

No commits in common. "761babfa1af4c4a2f6694e0dfceba404627335f0" and "ad3c77b40eb738212cfb4710a009f36831e19a32" have entirely different histories.

3 changed files with 120 additions and 178 deletions

View File

@ -1,50 +1,49 @@
package db package db
import ( import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"time" "time"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
) )
var connPool *pgxpool.Pool var connPool *pgxpool.Pool
func InitDB(connString string) error { func InitDB(connString string) error {
poolConfig, err := pgxpool.ParseConfig(connString) poolConfig, err := pgxpool.ParseConfig(connString)
if err != nil { if err != nil {
return fmt.Errorf("error while parsing connection string: %w", err) return fmt.Errorf("error while parsing connection string: %w", err)
} }
poolConfig.MaxConns = 100 poolConfig.MaxConns = 100
poolConfig.MinConns = 0 poolConfig.MinConns = 0
poolConfig.MaxConnLifetime = time.Hour poolConfig.MaxConnLifetime = time.Hour
poolConfig.HealthCheckPeriod = 30 * time.Second poolConfig.HealthCheckPeriod = 30 * time.Second
connPool, err = pgxpool.NewWithConfig(context.Background(), poolConfig) connPool, err = pgxpool.NewWithConfig(context.Background(), poolConfig)
if err != nil { if err != nil {
return fmt.Errorf("error while initializing DB connections pool: %w", err) return fmt.Errorf("error while initializing DB connections pool: %w", err)
} }
return nil return nil
} }
func transaction(handler func(context.Context, pgx.Tx) (statusCode int, err error)) (statusCode int, err error) { func transaction(ctx context.Context, handler func(pgx.Tx) (statusCode int, err error)) (statusCode int, err error) {
ctx := context.Background() tx, err := connPool.Begin(ctx)
tx, err := connPool.Begin(ctx) if err != nil {
if err != nil { statusCode = http.StatusInternalServerError
statusCode = http.StatusInternalServerError return
return }
} statusCode, err = handler(tx)
statusCode, err = handler(ctx, tx) if err != nil {
if err != nil { tx.Rollback(ctx)
tx.Rollback(ctx) return
return }
} err = tx.Commit(ctx)
err = tx.Commit(ctx) if err != nil {
if err != nil { statusCode = http.StatusInternalServerError
statusCode = http.StatusInternalServerError }
} return
return }
}

View File

@ -1,53 +0,0 @@
package db
import (
"fmt"
"net/http"
"strconv"
"strings"
)
// Convert "filter" URL param to SQL "WHERE" condition
func filterToSQL(filter string) (sql string, statusCode int, err error) {
// filterTokens := strings.Split(string(filter), ";")
sql = "(true)"
return
}
// Convert "sort" URL param to SQL "ORDER BY"
func sortToSQL(sort string) (sql string, statusCode int, err error) {
if sort == "" {
return
}
sortOptions := strings.Split(sort, ",")
sql = " ORDER BY "
for i, sortOption := range sortOptions {
sortOrder := sortOption[:1]
sortColumn := sortOption[1:]
// parse sorting order marker
switch sortOrder {
case "+":
sortOrder = "ASC"
case "-":
sortOrder = "DESC"
default:
err = fmt.Errorf("invalid sorting order mark: %q", sortOrder)
statusCode = http.StatusBadRequest
return
}
// validate sorting column
var n int
n, err = strconv.Atoi(sortColumn)
if err != nil || n < 0 {
err = fmt.Errorf("invalid sorting column: %q", sortColumn)
statusCode = http.StatusBadRequest
return
}
// add sorting option to query
if i > 0 {
sql += ","
}
sql += fmt.Sprintf("%s %s NULLS LAST", sortColumn, sortOrder)
}
return
}

View File

@ -1,75 +1,71 @@
package models package models
import ( import "time"
"time"
type User struct {
"github.com/jackc/pgx/v5/pgtype" Name string `json:"name"`
) IsAdmin bool `json:"is_admin"`
}
type User struct {
Name string `json:"name"` type MIME struct {
IsAdmin bool `json:"is_admin"` Name string `json:"name"`
} Extension string `json:"extension"`
}
type MIME struct {
Name string `json:"name"` type Category struct {
Extension string `json:"extension"` ID string `json:"id"`
} Name string `json:"name"`
Color string `json:"color"`
type Category struct { CreatedAt time.Time `json:"created_at"`
ID string `json:"id"` Creator User `json:"creator"`
Name string `json:"name"` }
Color pgtype.Text `json:"color"`
CreatedAt time.Time `json:"created_at"` type File struct {
Creator User `json:"creator"` ID string `json:"id"`
} Name string `json:"name"`
MIME MIME `json:"mime"`
type File struct { CreatedAt time.Time `json:"created_at"`
ID string `json:"id"` Creator User `json:"creator"`
Name pgtype.Text `json:"name"` }
MIME MIME `json:"mime"`
CreatedAt time.Time `json:"created_at"` type Tag struct {
Creator User `json:"creator"` ID string `json:"id"`
} Name string `json:"name"`
Color string `json:"color"`
type Tag struct { Category Category `json:"category"`
ID string `json:"id"` CreatedAt time.Time `json:"created_at"`
Name string `json:"name"` Creator User `json:"creator"`
Color pgtype.Text `json:"color"` }
Category Category `json:"category"`
CreatedAt time.Time `json:"created_at"` type Autotag struct {
Creator User `json:"creator"` TriggerTag Tag `json:"trigger_tag"`
} AddTag Tag `json:"add_tag"`
IsActive bool `json:"is_active"`
type Autotag struct { }
TriggerTag Tag `json:"trigger_tag"`
AddTag Tag `json:"add_tag"` type Pool struct {
IsActive bool `json:"is_active"` ID string `json:"id"`
} Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
type Pool struct { Creator User `json:"creator"`
ID string `json:"id"` }
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"` type Session struct {
Creator User `json:"creator"` ID int `json:"id"`
} UserAgent string `json:"user_agent"`
StartedAt time.Time `json:"started_at"`
type Session struct { ExpiresAt time.Time `json:"expires_at"`
ID int `json:"id"` LastActivity time.Time `json:"last_activity"`
UserAgent string `json:"user_agent"` }
StartedAt time.Time `json:"started_at"`
ExpiresAt time.Time `json:"expires_at"` type Pagination struct {
LastActivity time.Time `json:"last_activity"` Total int `json:"total"`
} Offset int `json:"offset"`
Limit int `json:"limit"`
type Pagination struct { Count int `json:"count"`
Total int `json:"total"` }
Offset int `json:"offset"`
Limit int `json:"limit"` type Slice[T any] struct {
Count int `json:"count"` Pagination Pagination `json:"pagination"`
} Data []T `json:"data"`
}
type Slice[T any] struct {
Pagination Pagination `json:"pagination"`
Data []T `json:"data"`
}