mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-06-08 14:53:46 +00:00
fix(handler): validate nested request structure for relations
* added checks for valid _request values in single and multiple relations * introduced isValidNestedRequest function to encapsulate validation logic fix(crud): expand operation handling for nested CUD * added "add" to insert operations and "modify" to update operations * included "remove" in delete operations
This commit is contained in:
@@ -113,7 +113,7 @@ func (p *NestedCUDProcessor) ProcessNestedCUD(
|
||||
|
||||
// Process based on operation
|
||||
switch strings.ToLower(operation) {
|
||||
case "insert", "create":
|
||||
case "insert", "create", "add":
|
||||
// Only perform insert if we have data to insert
|
||||
if hasData {
|
||||
id, err := p.processInsert(ctx, regularData, tableName)
|
||||
@@ -141,7 +141,7 @@ func (p *NestedCUDProcessor) ProcessNestedCUD(
|
||||
logger.Debug("Skipping insert for %s - no data columns besides _request", tableName)
|
||||
}
|
||||
|
||||
case "update", "change":
|
||||
case "update", "change", "modify":
|
||||
// Only perform update if we have data to update
|
||||
if reflection.IsEmptyValue(data[pkName]) {
|
||||
logger.Warn("Skipping update for %s - no primary key", tableName)
|
||||
@@ -174,7 +174,7 @@ func (p *NestedCUDProcessor) ProcessNestedCUD(
|
||||
result.ID = data[pkName]
|
||||
}
|
||||
|
||||
case "delete":
|
||||
case "delete", "remove":
|
||||
if reflection.IsEmptyValue(data[pkName]) {
|
||||
logger.Warn("Skipping delete for %s - no primary key", tableName)
|
||||
return result, nil
|
||||
|
||||
@@ -2043,7 +2043,10 @@ func (h *Handler) processChildRelationsForField(
|
||||
// Process based on relation type and data structure
|
||||
switch v := relationValue.(type) {
|
||||
case map[string]interface{}:
|
||||
// Single related object - add parent ID to foreign key field
|
||||
if !isValidNestedRequest(v) {
|
||||
logger.Debug("Skipping single relation %s - missing or invalid _request value", relationName)
|
||||
return nil
|
||||
}
|
||||
// IMPORTANT: In recursive relationships, don't overwrite the primary key
|
||||
if parentID != nil && foreignKeyFieldName != "" && foreignKeyFieldName != childPKFieldName {
|
||||
v[foreignKeyFieldName] = parentID
|
||||
@@ -2060,7 +2063,10 @@ func (h *Handler) processChildRelationsForField(
|
||||
// Multiple related objects
|
||||
for i, item := range v {
|
||||
if itemMap, ok := item.(map[string]interface{}); ok {
|
||||
// Add parent ID to foreign key field
|
||||
if !isValidNestedRequest(itemMap) {
|
||||
logger.Debug("Skipping relation array[%d] %s - missing or invalid _request value", i, relationName)
|
||||
continue
|
||||
}
|
||||
// IMPORTANT: In recursive relationships, don't overwrite the primary key
|
||||
if parentID != nil && foreignKeyFieldName != "" && foreignKeyFieldName != childPKFieldName {
|
||||
itemMap[foreignKeyFieldName] = parentID
|
||||
@@ -2078,7 +2084,10 @@ func (h *Handler) processChildRelationsForField(
|
||||
case []map[string]interface{}:
|
||||
// Multiple related objects (typed slice)
|
||||
for i, itemMap := range v {
|
||||
// Add parent ID to foreign key field
|
||||
if !isValidNestedRequest(itemMap) {
|
||||
logger.Debug("Skipping relation typed array[%d] %s - missing or invalid _request value", i, relationName)
|
||||
continue
|
||||
}
|
||||
// IMPORTANT: In recursive relationships, don't overwrite the primary key
|
||||
if parentID != nil && foreignKeyFieldName != "" && foreignKeyFieldName != childPKFieldName {
|
||||
itemMap[foreignKeyFieldName] = parentID
|
||||
@@ -2099,6 +2108,24 @@ func (h *Handler) processChildRelationsForField(
|
||||
return nil
|
||||
}
|
||||
|
||||
// isValidNestedRequest returns true only when the item carries a _request key
|
||||
// whose value is one of the recognised mutation verbs.
|
||||
func isValidNestedRequest(item map[string]interface{}) bool {
|
||||
raw, ok := item["_request"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
s, ok := raw.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(s)) {
|
||||
case "insert", "create", "add", "change", "update", "modify", "delete", "remove":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getTableNameForRelatedModel gets the table name for a related model.
|
||||
// If the model's TableName() is schema-qualified (e.g. "public.users") the
|
||||
// separator is adjusted for the active driver: underscore for SQLite, dot otherwise.
|
||||
|
||||
Reference in New Issue
Block a user