Skip to content

Conversation

WilliamDeBruin
Copy link
Contributor

@WilliamDeBruin WilliamDeBruin commented Jun 30, 2025

Enable Interface Field Access in Rule Expressions

Problem Summary

The Grule Rule Engine cannot access fields on interface{} types in rule expressions, causing runtime errors when trying to navigate nested data structures.

Previously, rules like this would fail if Data.Payload has type any | interface{}:

rule "ExampleRule" {
    when
        Data.Type == "specific_type" &&
        Data.Payload.Status == "active"  // ❌ Error if Payload is interface{}
    then
        // take action
}

Root Cause

In /model/GoDataAccessLayer.go, the IsObject() method only recognized reflect.Struct and reflect.Ptr types as objects, but not reflect.Interface types that contain structs. This caused nested field access like Struct.InterfaceField.NestedField to fail when InterfaceField is an interface{} field.

Changes Made

Core Implementation

  • Enhanced IsObject() method: Checks if interface contains struct and extracts concrete value
  • Enhanced GetObjectValueByField() method: Handles interface types by extracting concrete values
  • Enhanced SetObjectValueByField() method: Supports setting values in interface fields for addressable types

Test Coverage

  • Added comprehensive unit tests in GoDataAccessLayer_test.go for interface field access
  • Added integration tests in examples/interface_field_access_test.go demonstrating real-world usage
  • Tests both reading and writing interface fields with various data types

Benefits

Enable direct field access on interface{} types in rules
Maintain backward compatibility with existing functionality
Simplify rule writing for complex data structures
Natural rule syntax that's intuitive for developers

Example Usage

After this fix, users can write natural rules:

rule "InterfaceFieldRule" {
    when
        Data.Type == "test" &&
        Data.Payload.Status == "active"  // ✅ Now works!
    then
        Data.Payload.Status = "processed";
        Log("Success");
}

Testing

All existing tests pass, and new tests verify:

  • Reading interface fields with struct values
  • Reading interface fields with pointer values
  • Writing to interface fields (when addressable)
  • Proper error handling for non-addressable cases
  • Backward compatibility with existing object access patterns

Backwards Compatibility

This change is fully backwards compatible. All existing code continues to work unchanged, and the enhancement only adds new capabilities for interface field access.


Files Modified:

  • model/GoDataAccessLayer.go - Core implementation
  • model/GoDataAccessLayer_test.go - Unit tests
  • examples/interface_field_access_test.go - Integration tests (new file)

- Enhanced IsObject() method to recognize interfaces containing structs
- Updated GetObjectValueByField() to handle interface types
- Updated SetObjectValueByField() to support interface field modification
- Added comprehensive tests for interface field access
- Enables direct field access like Data.Payload.Status in rules
- Maintains backward compatibility with existing functionality

Fixes issue where interface{} fields could not be accessed directly
in rule expressions, requiring workaround accessor methods.
Copy link
Member

@newm4n newm4n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the contribution. LGTM

@newm4n newm4n merged commit bfe6d8f into hyperjumptech:master Jul 1, 2025
1 check passed
@newm4n
Copy link
Member

newm4n commented Jul 1, 2025

IMHO, this is part of the core improvement. I will make a new release because of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants