mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-06 14:26:22 +00:00
161 lines
5.0 KiB
Go
161 lines
5.0 KiB
Go
package funcspec
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/bitechdev/ResolveSpec/pkg/logger"
|
|
"github.com/bitechdev/ResolveSpec/pkg/security"
|
|
)
|
|
|
|
// HookType defines the type of hook to execute
|
|
type HookType string
|
|
|
|
const (
|
|
// Query operation hooks (for SqlQuery - single record)
|
|
BeforeQuery HookType = "before_query"
|
|
AfterQuery HookType = "after_query"
|
|
|
|
// Query list operation hooks (for SqlQueryList - multiple records)
|
|
BeforeQueryList HookType = "before_query_list"
|
|
AfterQueryList HookType = "after_query_list"
|
|
|
|
// SQL execution hooks (just before SQL is executed)
|
|
BeforeSQLExec HookType = "before_sql_exec"
|
|
AfterSQLExec HookType = "after_sql_exec"
|
|
|
|
// Response hooks (before response is sent)
|
|
BeforeResponse HookType = "before_response"
|
|
)
|
|
|
|
// HookContext contains all the data available to a hook
|
|
type HookContext struct {
|
|
Context context.Context
|
|
Handler *Handler // Reference to the handler for accessing database
|
|
Request *http.Request
|
|
Writer http.ResponseWriter
|
|
|
|
// SQL query and variables
|
|
SQLQuery string // The SQL query being executed (can be modified by hooks)
|
|
Variables map[string]interface{} // Variables extracted from request
|
|
InputVars []string // Input variable placeholders found in query
|
|
MetaInfo map[string]interface{} // Metadata about the request
|
|
PropQry map[string]string // Property query parameters
|
|
|
|
// User context
|
|
UserContext *security.UserContext
|
|
|
|
// Pagination and filtering (for list queries)
|
|
SortColumns string
|
|
Limit int
|
|
Offset int
|
|
|
|
// Results
|
|
Result interface{} // Query result (single record or list)
|
|
Total int64 // Total count (for list queries)
|
|
Error error // Error if operation failed
|
|
ComplexAPI bool // Whether complex API response format is requested
|
|
NoCount bool // Whether count query should be skipped
|
|
BlankParams bool // Whether blank parameters should be removed
|
|
AllowFilter bool // Whether filtering is allowed
|
|
|
|
// Allow hooks to abort the operation
|
|
Abort bool // If set to true, the operation will be aborted
|
|
AbortMessage string // Message to return if aborted
|
|
AbortCode int // HTTP status code if aborted
|
|
}
|
|
|
|
// HookFunc is the signature for hook functions
|
|
// It receives a HookContext and can modify it or return an error
|
|
// If an error is returned, the operation will be aborted
|
|
type HookFunc func(*HookContext) error
|
|
|
|
// HookRegistry manages all registered hooks
|
|
type HookRegistry struct {
|
|
hooks map[HookType][]HookFunc
|
|
}
|
|
|
|
// NewHookRegistry creates a new hook registry
|
|
func NewHookRegistry() *HookRegistry {
|
|
return &HookRegistry{
|
|
hooks: make(map[HookType][]HookFunc),
|
|
}
|
|
}
|
|
|
|
// Register adds a new hook for the specified hook type
|
|
func (r *HookRegistry) Register(hookType HookType, hook HookFunc) {
|
|
if r.hooks == nil {
|
|
r.hooks = make(map[HookType][]HookFunc)
|
|
}
|
|
r.hooks[hookType] = append(r.hooks[hookType], hook)
|
|
logger.Info("Registered funcspec hook for %s (total: %d)", hookType, len(r.hooks[hookType]))
|
|
}
|
|
|
|
// RegisterMultiple registers a hook for multiple hook types
|
|
func (r *HookRegistry) RegisterMultiple(hookTypes []HookType, hook HookFunc) {
|
|
for _, hookType := range hookTypes {
|
|
r.Register(hookType, hook)
|
|
}
|
|
}
|
|
|
|
// Execute runs all hooks for the specified type in order
|
|
// If any hook returns an error, execution stops and the error is returned
|
|
func (r *HookRegistry) Execute(hookType HookType, ctx *HookContext) error {
|
|
hooks, exists := r.hooks[hookType]
|
|
if !exists || len(hooks) == 0 {
|
|
return nil
|
|
}
|
|
|
|
logger.Debug("Executing %d funcspec hook(s) for %s", len(hooks), hookType)
|
|
|
|
for i, hook := range hooks {
|
|
if err := hook(ctx); err != nil {
|
|
logger.Error("Funcspec hook %d for %s failed: %v", i+1, hookType, err)
|
|
return fmt.Errorf("hook execution failed: %w", err)
|
|
}
|
|
|
|
// Check if hook requested abort
|
|
if ctx.Abort {
|
|
logger.Warn("Funcspec hook %d for %s requested abort: %s", i+1, hookType, ctx.AbortMessage)
|
|
return fmt.Errorf("operation aborted by hook: %s", ctx.AbortMessage)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Clear removes all hooks for the specified type
|
|
func (r *HookRegistry) Clear(hookType HookType) {
|
|
delete(r.hooks, hookType)
|
|
logger.Info("Cleared all funcspec hooks for %s", hookType)
|
|
}
|
|
|
|
// ClearAll removes all registered hooks
|
|
func (r *HookRegistry) ClearAll() {
|
|
r.hooks = make(map[HookType][]HookFunc)
|
|
logger.Info("Cleared all funcspec hooks")
|
|
}
|
|
|
|
// Count returns the number of hooks registered for a specific type
|
|
func (r *HookRegistry) Count(hookType HookType) int {
|
|
if hooks, exists := r.hooks[hookType]; exists {
|
|
return len(hooks)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// HasHooks returns true if there are any hooks registered for the specified type
|
|
func (r *HookRegistry) HasHooks(hookType HookType) bool {
|
|
return r.Count(hookType) > 0
|
|
}
|
|
|
|
// GetAllHookTypes returns all hook types that have registered hooks
|
|
func (r *HookRegistry) GetAllHookTypes() []HookType {
|
|
types := make([]HookType, 0, len(r.hooks))
|
|
for hookType := range r.hooks {
|
|
types = append(types, hookType)
|
|
}
|
|
return types
|
|
}
|