Added Tx common.Database to hooks

This commit is contained in:
Hein 2025-12-12 09:45:44 +02:00
parent 31ad217818
commit 2f18dde29c
4 changed files with 61 additions and 0 deletions

View File

@ -56,6 +56,10 @@ type HookContext struct {
Abort bool // If set to true, the operation will be aborted Abort bool // If set to true, the operation will be aborted
AbortMessage string // Message to return if aborted AbortMessage string // Message to return if aborted
AbortCode int // HTTP status code if aborted AbortCode int // HTTP status code if aborted
// Tx provides access to the database/transaction for executing additional SQL
// This allows hooks to run custom queries in addition to the main Query chain
Tx common.Database
} }
// HookFunc is the signature for hook functions // HookFunc is the signature for hook functions

View File

@ -300,6 +300,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
Options: options, Options: options,
ID: id, ID: id,
Writer: w, Writer: w,
Tx: h.db,
} }
if err := h.hooks.Execute(BeforeRead, hookCtx); err != nil { if err := h.hooks.Execute(BeforeRead, hookCtx); err != nil {
@ -866,6 +867,7 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
Options: options, Options: options,
Data: data, Data: data,
Writer: w, Writer: w,
Tx: h.db,
} }
if err := h.hooks.Execute(BeforeCreate, hookCtx); err != nil { if err := h.hooks.Execute(BeforeCreate, hookCtx); err != nil {
@ -955,6 +957,7 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
Data: modelValue, Data: modelValue,
Writer: w, Writer: w,
Query: query, Query: query,
Tx: tx,
} }
if err := h.hooks.Execute(BeforeScan, itemHookCtx); err != nil { if err := h.hooks.Execute(BeforeScan, itemHookCtx); err != nil {
return fmt.Errorf("BeforeScan hook failed for item %d: %w", i, err) return fmt.Errorf("BeforeScan hook failed for item %d: %w", i, err)
@ -1047,6 +1050,7 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, id
Schema: schema, Schema: schema,
Entity: entity, Entity: entity,
TableName: tableName, TableName: tableName,
Tx: h.db,
Model: model, Model: model,
Options: options, Options: options,
ID: id, ID: id,
@ -1122,6 +1126,7 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, id
// Execute BeforeScan hooks - pass query chain so hooks can modify it // Execute BeforeScan hooks - pass query chain so hooks can modify it
hookCtx.Query = query hookCtx.Query = query
hookCtx.Tx = tx
if err := h.hooks.Execute(BeforeScan, hookCtx); err != nil { if err := h.hooks.Execute(BeforeScan, hookCtx); err != nil {
return fmt.Errorf("BeforeScan hook failed: %w", err) return fmt.Errorf("BeforeScan hook failed: %w", err)
} }
@ -1217,6 +1222,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
Model: model, Model: model,
ID: itemID, ID: itemID,
Writer: w, Writer: w,
Tx: tx,
} }
if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil { if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil {
@ -1285,6 +1291,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
Model: model, Model: model,
ID: itemIDStr, ID: itemIDStr,
Writer: w, Writer: w,
Tx: tx,
} }
if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil { if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil {
@ -1337,6 +1344,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
Model: model, Model: model,
ID: itemIDStr, ID: itemIDStr,
Writer: w, Writer: w,
Tx: tx,
} }
if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil { if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil {
@ -1390,6 +1398,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
Model: model, Model: model,
ID: id, ID: id,
Writer: w, Writer: w,
Tx: h.db,
} }
if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil { if err := h.hooks.Execute(BeforeDelete, hookCtx); err != nil {

View File

@ -55,6 +55,10 @@ type HookContext struct {
// Response writer - allows hooks to modify response // Response writer - allows hooks to modify response
Writer common.ResponseWriter Writer common.ResponseWriter
// Tx provides access to the database/transaction for executing additional SQL
// This allows hooks to run custom queries in addition to the main Query chain
Tx common.Database
} }
// HookFunc is the signature for hook functions // HookFunc is the signature for hook functions

View File

@ -150,6 +150,50 @@ func ExampleRelatedDataHook(ctx *HookContext) error {
return nil return nil
} }
// ExampleTxHook demonstrates using the Tx field to execute additional SQL queries
// The Tx field provides access to the database/transaction for custom queries
func ExampleTxHook(ctx *HookContext) error {
// Example: Execute additional SQL operations alongside the main query
// This is useful for maintaining data consistency, updating related records, etc.
if ctx.Entity == "orders" && ctx.Data != nil {
// Example: Update inventory when an order is created
// Extract product ID and quantity from the order data
// dataMap, ok := ctx.Data.(map[string]interface{})
// if !ok {
// return fmt.Errorf("invalid data format")
// }
// productID := dataMap["product_id"]
// quantity := dataMap["quantity"]
// Use ctx.Tx to execute additional SQL queries
// The Tx field contains the same database/transaction as the main operation
// If inside a transaction, your queries will be part of the same transaction
// query := ctx.Tx.NewUpdate().
// Table("inventory").
// Set("quantity = quantity - ?", quantity).
// Where("product_id = ?", productID)
//
// if _, err := query.Exec(ctx.Context); err != nil {
// logger.Error("Failed to update inventory: %v", err)
// return fmt.Errorf("failed to update inventory: %w", err)
// }
// You can also execute raw SQL using ctx.Tx
// var result []map[string]interface{}
// err := ctx.Tx.Query(ctx.Context, &result,
// "INSERT INTO order_history (order_id, status) VALUES (?, ?)",
// orderID, "pending")
// if err != nil {
// return fmt.Errorf("failed to insert order history: %w", err)
// }
logger.Debug("Executed additional SQL for order entity")
}
return nil
}
// SetupExampleHooks demonstrates how to register hooks on a handler // SetupExampleHooks demonstrates how to register hooks on a handler
func SetupExampleHooks(handler *Handler) { func SetupExampleHooks(handler *Handler) {
hooks := handler.Hooks() hooks := handler.Hooks()