mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-01-17 00:14:26 +00:00
feat(restheadspec): ✨ Add custom SQL JOIN support
- Introduced `x-custom-sql-join` header for custom SQL JOIN clauses. - Supports single and multiple JOINs, separated by `|`. - Enhanced query handling to apply custom JOINs directly. - Updated documentation to reflect new functionality. - Added tests for parsing custom SQL JOINs from query parameters and headers.
This commit is contained in:
@@ -26,7 +26,8 @@ type ExtendedRequestOptions struct {
|
||||
CustomSQLOr string
|
||||
|
||||
// Joins
|
||||
Expand []ExpandOption
|
||||
Expand []ExpandOption
|
||||
CustomSQLJoin []string // Custom SQL JOIN clauses
|
||||
|
||||
// Advanced features
|
||||
AdvancedSQL map[string]string // Column -> SQL expression
|
||||
@@ -111,6 +112,7 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request, model interface{}) E
|
||||
AdvancedSQL: make(map[string]string),
|
||||
ComputedQL: make(map[string]string),
|
||||
Expand: make([]ExpandOption, 0),
|
||||
CustomSQLJoin: make([]string, 0),
|
||||
ResponseFormat: "simple", // Default response format
|
||||
SingleRecordAsObject: true, // Default: normalize single-element arrays to objects
|
||||
}
|
||||
@@ -185,8 +187,7 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request, model interface{}) E
|
||||
case strings.HasPrefix(key, "x-expand"):
|
||||
h.parseExpand(&options, decodedValue)
|
||||
case strings.HasPrefix(key, "x-custom-sql-join"):
|
||||
// TODO: Implement custom SQL join
|
||||
logger.Debug("Custom SQL join not yet implemented: %s", decodedValue)
|
||||
h.parseCustomSQLJoin(&options, decodedValue)
|
||||
|
||||
// Sorting & Pagination
|
||||
case strings.HasPrefix(key, "x-sort"):
|
||||
@@ -495,6 +496,43 @@ func (h *Handler) parseExpand(options *ExtendedRequestOptions, value string) {
|
||||
}
|
||||
}
|
||||
|
||||
// parseCustomSQLJoin parses x-custom-sql-join header
|
||||
// Format: Single JOIN clause or multiple JOIN clauses separated by |
|
||||
// Example: "LEFT JOIN departments d ON d.id = employees.department_id"
|
||||
// Example: "LEFT JOIN departments d ON d.id = e.dept_id | INNER JOIN roles r ON r.id = e.role_id"
|
||||
func (h *Handler) parseCustomSQLJoin(options *ExtendedRequestOptions, value string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Split by | for multiple joins
|
||||
joins := strings.Split(value, "|")
|
||||
for _, joinStr := range joins {
|
||||
joinStr = strings.TrimSpace(joinStr)
|
||||
if joinStr == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Basic validation: should contain "JOIN" keyword
|
||||
upperJoin := strings.ToUpper(joinStr)
|
||||
if !strings.Contains(upperJoin, "JOIN") {
|
||||
logger.Warn("Invalid custom SQL join (missing JOIN keyword): %s", joinStr)
|
||||
continue
|
||||
}
|
||||
|
||||
// Sanitize the join clause using common.SanitizeWhereClause
|
||||
// Note: This is basic sanitization - in production you may want stricter validation
|
||||
sanitizedJoin := common.SanitizeWhereClause(joinStr, "", nil)
|
||||
if sanitizedJoin == "" {
|
||||
logger.Warn("Custom SQL join failed sanitization: %s", joinStr)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Debug("Adding custom SQL join: %s", sanitizedJoin)
|
||||
options.CustomSQLJoin = append(options.CustomSQLJoin, sanitizedJoin)
|
||||
}
|
||||
}
|
||||
|
||||
// parseSorting parses x-sort header
|
||||
// Format: +field1,-field2,field3 (+ for ASC, - for DESC, default ASC)
|
||||
func (h *Handler) parseSorting(options *ExtendedRequestOptions, value string) {
|
||||
|
||||
Reference in New Issue
Block a user