Fixed formatting issues
Some checks failed
Tests / Run Tests (1.23.x) (push) Has been cancelled
Tests / Run Tests (1.24.x) (push) Has been cancelled
Tests / Lint Code (push) Has been cancelled
Tests / Build (push) Has been cancelled

This commit is contained in:
Hein 2025-12-01 14:56:30 +02:00
parent 1643a5e920
commit 78029fb34f
10 changed files with 77 additions and 64 deletions

2
pkg/cache/cache.go vendored
View File

@ -47,7 +47,7 @@ func UseMemcache(config *MemcacheConfig) error {
// Initializes with in-memory provider if not already initialized. // Initializes with in-memory provider if not already initialized.
func GetDefaultCache() *Cache { func GetDefaultCache() *Cache {
if defaultCache == nil { if defaultCache == nil {
UseMemory(&Options{ _ = UseMemory(&Options{
DefaultTTL: 5 * time.Minute, DefaultTTL: 5 * time.Minute,
MaxSize: 10000, MaxSize: 10000,
}) })

View File

@ -17,7 +17,6 @@ func ExampleInMemoryCache() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer Close()
ctx := context.Background() ctx := context.Background()
@ -33,6 +32,7 @@ func ExampleInMemoryCache() {
user := User{ID: 1, Name: "John Doe"} user := User{ID: 1, Name: "John Doe"}
err = cache.Set(ctx, "user:1", user, 10*time.Minute) err = cache.Set(ctx, "user:1", user, 10*time.Minute)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
@ -40,6 +40,7 @@ func ExampleInMemoryCache() {
var retrieved User var retrieved User
err = cache.Get(ctx, "user:1", &retrieved) err = cache.Get(ctx, "user:1", &retrieved)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
@ -52,15 +53,18 @@ func ExampleInMemoryCache() {
// Delete a key // Delete a key
err = cache.Delete(ctx, "user:1") err = cache.Delete(ctx, "user:1")
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
// Get statistics // Get statistics
stats, err := cache.Stats(ctx) stats, err := cache.Stats(ctx)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
fmt.Printf("Cache stats: %+v\n", stats) fmt.Printf("Cache stats: %+v\n", stats)
_ = Close()
} }
// ExampleRedisCache demonstrates using the Redis cache provider. // ExampleRedisCache demonstrates using the Redis cache provider.
@ -78,7 +82,6 @@ func ExampleRedisCache() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer Close()
ctx := context.Background() ctx := context.Background()
@ -89,12 +92,14 @@ func ExampleRedisCache() {
data := []byte("Hello, Redis!") data := []byte("Hello, Redis!")
err = cache.SetBytes(ctx, "greeting", data, 1*time.Hour) err = cache.SetBytes(ctx, "greeting", data, 1*time.Hour)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
// Retrieve raw bytes // Retrieve raw bytes
retrieved, err := cache.GetBytes(ctx, "greeting") retrieved, err := cache.GetBytes(ctx, "greeting")
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
@ -103,8 +108,10 @@ func ExampleRedisCache() {
// Clear all cache // Clear all cache
err = cache.Clear(ctx) err = cache.Clear(ctx)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
_ = Close()
} }
// ExampleMemcacheCache demonstrates using the Memcache cache provider. // ExampleMemcacheCache demonstrates using the Memcache cache provider.
@ -119,7 +126,6 @@ func ExampleMemcacheCache() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer Close()
ctx := context.Background() ctx := context.Background()
@ -136,6 +142,7 @@ func ExampleMemcacheCache() {
product := Product{ID: 100, Name: "Widget", Price: 29.99} product := Product{ID: 100, Name: "Widget", Price: 29.99}
err = cache.Set(ctx, "product:100", product, 30*time.Minute) err = cache.Set(ctx, "product:100", product, 30*time.Minute)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
@ -143,10 +150,12 @@ func ExampleMemcacheCache() {
var retrieved Product var retrieved Product
err = cache.Get(ctx, "product:100", &retrieved) err = cache.Get(ctx, "product:100", &retrieved)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
fmt.Printf("Retrieved product: %+v\n", retrieved) fmt.Printf("Retrieved product: %+v\n", retrieved)
_ = Close()
} }
// ExampleGetOrSet demonstrates the GetOrSet pattern for lazy loading. // ExampleGetOrSet demonstrates the GetOrSet pattern for lazy loading.
@ -158,7 +167,6 @@ func ExampleGetOrSet() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer Close()
ctx := context.Background() ctx := context.Background()
cache := GetDefaultCache() cache := GetDefaultCache()
@ -175,6 +183,7 @@ func ExampleGetOrSet() {
return ExpensiveData{Result: "computed value"}, nil return ExpensiveData{Result: "computed value"}, nil
}) })
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
@ -186,10 +195,12 @@ func ExampleGetOrSet() {
return ExpensiveData{Result: "new value"}, nil return ExpensiveData{Result: "new value"}, nil
}) })
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
fmt.Printf("Cached data: %+v\n", data) fmt.Printf("Cached data: %+v\n", data)
_ = Close()
} }
// ExampleCustomProvider demonstrates using a custom provider. // ExampleCustomProvider demonstrates using a custom provider.
@ -202,7 +213,6 @@ func ExampleCustomProvider() {
// Initialize with custom provider // Initialize with custom provider
Initialize(memProvider) Initialize(memProvider)
defer Close()
ctx := context.Background() ctx := context.Background()
cache := GetDefaultCache() cache := GetDefaultCache()
@ -210,6 +220,7 @@ func ExampleCustomProvider() {
// Use the cache // Use the cache
err := cache.SetBytes(ctx, "key", []byte("value"), 5*time.Minute) err := cache.SetBytes(ctx, "key", []byte("value"), 5*time.Minute)
if err != nil { if err != nil {
_ = Close()
log.Fatal(err) log.Fatal(err)
} }
@ -218,6 +229,7 @@ func ExampleCustomProvider() {
count := mp.CleanExpired(ctx) count := mp.CleanExpired(ctx)
fmt.Printf("Cleaned %d expired items\n", count) fmt.Printf("Cleaned %d expired items\n", count)
} }
_ = Close()
} }
// ExampleDeleteByPattern demonstrates pattern-based deletion (Redis only). // ExampleDeleteByPattern demonstrates pattern-based deletion (Redis only).
@ -232,21 +244,23 @@ func ExampleDeleteByPattern() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer Close()
ctx := context.Background() ctx := context.Background()
cache := GetDefaultCache() cache := GetDefaultCache()
// Store multiple keys with a pattern // Store multiple keys with a pattern
cache.SetBytes(ctx, "user:1:profile", []byte("profile1"), 10*time.Minute) _ = cache.SetBytes(ctx, "user:1:profile", []byte("profile1"), 10*time.Minute)
cache.SetBytes(ctx, "user:2:profile", []byte("profile2"), 10*time.Minute) _ = cache.SetBytes(ctx, "user:2:profile", []byte("profile2"), 10*time.Minute)
cache.SetBytes(ctx, "user:1:settings", []byte("settings1"), 10*time.Minute) _ = cache.SetBytes(ctx, "user:1:settings", []byte("settings1"), 10*time.Minute)
// Delete all keys matching pattern (Redis glob pattern) // Delete all keys matching pattern (Redis glob pattern)
err = cache.DeleteByPattern(ctx, "user:*:profile") err = cache.DeleteByPattern(ctx, "user:*:profile")
if err != nil { if err != nil {
log.Fatal(err) _ = Close()
log.Print(err)
return
} }
fmt.Println("Deleted all user profile keys") fmt.Println("Deleted all user profile keys")
_ = Close()
} }

View File

@ -37,10 +37,10 @@ type Provider interface {
// CacheStats contains cache statistics. // CacheStats contains cache statistics.
type CacheStats struct { type CacheStats struct {
Hits int64 `json:"hits"` Hits int64 `json:"hits"`
Misses int64 `json:"misses"` Misses int64 `json:"misses"`
Keys int64 `json:"keys"` Keys int64 `json:"keys"`
ProviderType string `json:"provider_type"` ProviderType string `json:"provider_type"`
ProviderStats map[string]any `json:"provider_stats,omitempty"` ProviderStats map[string]any `json:"provider_stats,omitempty"`
} }

View File

@ -13,15 +13,15 @@ import (
// QueryCacheKey represents the components used to build a cache key for query total count // QueryCacheKey represents the components used to build a cache key for query total count
type QueryCacheKey struct { type QueryCacheKey struct {
TableName string `json:"table_name"` TableName string `json:"table_name"`
Filters []common.FilterOption `json:"filters"` Filters []common.FilterOption `json:"filters"`
Sort []common.SortOption `json:"sort"` Sort []common.SortOption `json:"sort"`
CustomSQLWhere string `json:"custom_sql_where,omitempty"` CustomSQLWhere string `json:"custom_sql_where,omitempty"`
CustomSQLOr string `json:"custom_sql_or,omitempty"` CustomSQLOr string `json:"custom_sql_or,omitempty"`
Expand []ExpandOptionKey `json:"expand,omitempty"` Expand []ExpandOptionKey `json:"expand,omitempty"`
Distinct bool `json:"distinct,omitempty"` Distinct bool `json:"distinct,omitempty"`
CursorForward string `json:"cursor_forward,omitempty"` CursorForward string `json:"cursor_forward,omitempty"`
CursorBackward string `json:"cursor_backward,omitempty"` CursorBackward string `json:"cursor_backward,omitempty"`
} }
// ExpandOptionKey represents expand options for cache key // ExpandOptionKey represents expand options for cache key

View File

@ -109,7 +109,7 @@ func (h *Handler) SqlQueryList(sqlquery string, pNoCount, pBlankparms, pAllowFil
// Use potentially modified SQL query and variables from hooks // Use potentially modified SQL query and variables from hooks
sqlquery = hookCtx.SQLQuery sqlquery = hookCtx.SQLQuery
variables = hookCtx.Variables variables = hookCtx.Variables
complexAPI = hookCtx.ComplexAPI // complexAPI = hookCtx.ComplexAPI
// Extract input variables from SQL query (placeholders like [variable]) // Extract input variables from SQL query (placeholders like [variable])
sqlquery = h.extractInputVariables(sqlquery, &inputvars) sqlquery = h.extractInputVariables(sqlquery, &inputvars)
@ -299,7 +299,7 @@ func (h *Handler) SqlQueryList(sqlquery string, pNoCount, pBlankparms, pAllowFil
} }
if len(dbobjlist) == 0 { if len(dbobjlist) == 0 {
w.Write([]byte("[]")) _, _ = w.Write([]byte("[]"))
return return
} }
@ -318,7 +318,7 @@ func (h *Handler) SqlQueryList(sqlquery string, pNoCount, pBlankparms, pAllowFil
if int64(len(dbobjlist)) < total { if int64(len(dbobjlist)) < total {
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
} }
w.Write(data) _, _ = w.Write(data)
} }
case "detail": case "detail":
@ -337,7 +337,7 @@ func (h *Handler) SqlQueryList(sqlquery string, pNoCount, pBlankparms, pAllowFil
if int64(len(dbobjlist)) < total { if int64(len(dbobjlist)) < total {
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
} }
w.Write(data) _, _ = w.Write(data)
} }
default: default:
@ -357,7 +357,7 @@ func (h *Handler) SqlQueryList(sqlquery string, pNoCount, pBlankparms, pAllowFil
if int64(len(dbobjlist)) < total { if int64(len(dbobjlist)) < total {
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
} }
w.Write(data) _, _ = w.Write(data)
} }
} else { } else {
data, err := json.Marshal(dbobjlist) data, err := json.Marshal(dbobjlist)
@ -367,7 +367,7 @@ func (h *Handler) SqlQueryList(sqlquery string, pNoCount, pBlankparms, pAllowFil
if int64(len(dbobjlist)) < total { if int64(len(dbobjlist)) < total {
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
} }
w.Write(data) _, _ = w.Write(data)
} }
} }
} }
@ -578,7 +578,7 @@ func (h *Handler) SqlQuery(sqlquery string, pBlankparms bool) HTTPFuncType {
if err != nil { if err != nil {
sendError(w, http.StatusInternalServerError, "json_error", "Could not marshal response", err) sendError(w, http.StatusInternalServerError, "json_error", "Could not marshal response", err)
} else { } else {
w.Write(data) _, _ = w.Write(data)
} }
return return
} }
@ -588,7 +588,7 @@ func (h *Handler) SqlQuery(sqlquery string, pBlankparms bool) HTTPFuncType {
if err != nil { if err != nil {
sendError(w, http.StatusInternalServerError, "json_error", "Could not marshal response", err) sendError(w, http.StatusInternalServerError, "json_error", "Could not marshal response", err)
} else { } else {
w.Write(data) _, _ = w.Write(data)
} }
} }
} }
@ -597,9 +597,9 @@ func (h *Handler) SqlQuery(sqlquery string, pBlankparms bool) HTTPFuncType {
// extractInputVariables extracts placeholders like [variable] from the SQL query // extractInputVariables extracts placeholders like [variable] from the SQL query
func (h *Handler) extractInputVariables(sqlquery string, inputvars *[]string) string { func (h *Handler) extractInputVariables(sqlquery string, inputvars *[]string) string {
max := strings.Count(sqlquery, "[") * 4
testsqlquery := sqlquery testsqlquery := sqlquery
for i := 0; i <= max; i++ { for i := 0; i <= strings.Count(sqlquery, "[")*4; i++ {
iStart := strings.Index(testsqlquery, "[") iStart := strings.Index(testsqlquery, "[")
if iStart < 0 { if iStart < 0 {
break break
@ -722,7 +722,7 @@ func (h *Handler) mergeHeaderParams(r *http.Request, sqlquery string, variables
} }
if strings.Contains(k, "x-simpleapi") { if strings.Contains(k, "x-simpleapi") {
*complexAPI = !(val == "1" || strings.ToLower(val) == "true") *complexAPI = !strings.EqualFold(val, "1") && !strings.EqualFold(val, "true")
} }
} }
return sqlquery return sqlquery
@ -904,5 +904,5 @@ func sendError(w http.ResponseWriter, status int, code, message string, err erro
"success": false, "success": false,
"error": errObj, "error": errObj,
}) })
w.Write(data) _, _ = w.Write(data)
} }

View File

@ -37,11 +37,11 @@ type HookContext struct {
Writer http.ResponseWriter Writer http.ResponseWriter
// SQL query and variables // SQL query and variables
SQLQuery string // The SQL query being executed (can be modified by hooks) SQLQuery string // The SQL query being executed (can be modified by hooks)
Variables map[string]interface{} // Variables extracted from request Variables map[string]interface{} // Variables extracted from request
InputVars []string // Input variable placeholders found in query InputVars []string // Input variable placeholders found in query
MetaInfo map[string]interface{} // Metadata about the request MetaInfo map[string]interface{} // Metadata about the request
PropQry map[string]string // Property query parameters PropQry map[string]string // Property query parameters
// User context // User context
UserContext *security.UserContext UserContext *security.UserContext

View File

@ -18,9 +18,9 @@ type RequestParameters struct {
Distinct bool Distinct bool
// Filtering // Filtering
FieldFilters map[string]string // column -> value (exact match) FieldFilters map[string]string // column -> value (exact match)
SearchFilters map[string]string // column -> value (ILIKE) SearchFilters map[string]string // column -> value (ILIKE)
SearchOps map[string]FilterOperator // column -> {operator, value, logic} SearchOps map[string]FilterOperator // column -> {operator, value, logic}
CustomSQLWhere string CustomSQLWhere string
CustomSQLOr string CustomSQLOr string
@ -51,10 +51,10 @@ func (h *Handler) ParseParameters(r *http.Request) *RequestParameters {
FieldFilters: make(map[string]string), FieldFilters: make(map[string]string),
SearchFilters: make(map[string]string), SearchFilters: make(map[string]string),
SearchOps: make(map[string]FilterOperator), SearchOps: make(map[string]FilterOperator),
Limit: 20, // Default limit Limit: 20, // Default limit
Offset: 0, // Default offset Offset: 0, // Default offset
ResponseFormat: "simple", // Default format ResponseFormat: "simple", // Default format
ComplexAPI: false, // Default to simple API ComplexAPI: false, // Default to simple API
} }
// Merge headers and query parameters // Merge headers and query parameters
@ -155,7 +155,7 @@ func (h *Handler) ParseParameters(r *http.Request) *RequestParameters {
// Response Format // Response Format
case strings.HasPrefix(key, "x-simpleapi"): case strings.HasPrefix(key, "x-simpleapi"):
params.ResponseFormat = "simple" params.ResponseFormat = "simple"
params.ComplexAPI = !(decodedValue == "1" || strings.EqualFold(decodedValue, "true")) params.ComplexAPI = decodedValue != "1" && !strings.EqualFold(decodedValue, "true")
case strings.HasPrefix(key, "x-detailapi"): case strings.HasPrefix(key, "x-detailapi"):
params.ResponseFormat = "detail" params.ResponseFormat = "detail"
params.ComplexAPI = true params.ComplexAPI = true

View File

@ -9,9 +9,9 @@ import (
// CompositeSecurityProvider combines multiple security providers // CompositeSecurityProvider combines multiple security providers
// Allows separating authentication, column security, and row security concerns // Allows separating authentication, column security, and row security concerns
type CompositeSecurityProvider struct { type CompositeSecurityProvider struct {
auth Authenticator auth Authenticator
colSec ColumnSecurityProvider colSec ColumnSecurityProvider
rowSec RowSecurityProvider rowSec RowSecurityProvider
} }
// NewCompositeSecurityProvider creates a composite provider // NewCompositeSecurityProvider creates a composite provider

View File

@ -377,4 +377,3 @@ func (a *DatabaseAuthenticatorExample) RefreshToken(ctx context.Context, refresh
ExpiresIn: int64(24 * time.Hour.Seconds()), ExpiresIn: int64(24 * time.Hour.Seconds()),
}, nil }, nil
} }

View File

@ -192,7 +192,7 @@ func (a *DatabaseAuthenticator) updateSessionActivity(ctx context.Context, sessi
var updatedUserJSON []byte var updatedUserJSON []byte
query := `SELECT p_success, p_error, p_user FROM resolvespec_session_update($1, $2::jsonb)` query := `SELECT p_success, p_error, p_user FROM resolvespec_session_update($1, $2::jsonb)`
a.db.QueryRowContext(ctx, query, sessionToken, userJSON).Scan(&success, &errorMsg, &updatedUserJSON) _ = a.db.QueryRowContext(ctx, query, sessionToken, userJSON).Scan(&success, &errorMsg, &updatedUserJSON)
} }
// RefreshToken implements Refreshable interface // RefreshToken implements Refreshable interface
@ -539,14 +539,14 @@ func generateRandomString(length int) string {
return string(b) return string(b)
} }
func getClaimString(claims map[string]any, key string) string { // func getClaimString(claims map[string]any, key string) string {
if claims == nil { // if claims == nil {
return "" // return ""
} // }
if val, ok := claims[key]; ok { // if val, ok := claims[key]; ok {
if str, ok := val.(string); ok { // if str, ok := val.(string); ok {
return str // return str
} // }
} // }
return "" // return ""
} // }