Repository: diegoholiveira/jsonlogic (go)

Issue:
Cannot specify a default value for a variable when accessing it on an array
When accessing a variable on an array, you cannot specify a default value for the variable. Is there a problem here?
rule: `{ "map":[{"var": "arr"},{"var":["xxx", "default"]}]}`
data: `{"arr": [{"xxx": "111","yyy": "222"},{"xxx": "333","yyy": "444"}]}`
result data: `[default default]`

Pull request description:
fix: ensure default values are used only when required
closes #110 


Patch:
diff --git a/arrays.go b/arrays.go
index 4b4e975..e78889b 100644
--- a/arrays.go
+++ b/arrays.go
@@ -2,7 +2,6 @@ package jsonlogic
 
 import (
 	"fmt"
-	"strings"
 
 	"github.com/diegoholiveira/jsonlogic/v3/internal/typing"
 )
@@ -66,14 +65,12 @@ func _map(values, data any) any {
 		return result
 	}
 
-	logic := solveVars(parsed[1], data)
+	logic := parsed[1]
 
 	for _, value := range subject.([]any) {
 		v := parseValues(logic, value)
 
-		if typing.IsTrue(v) || typing.IsNumber(v) || typing.IsBool(v) {
-			result = append(result, v)
-		}
+		result = append(result, v)
 	}
 
 	return result
@@ -150,195 +147,3 @@ func reduce(values, data any) any {
 
 	return context["accumulator"]
 }
-
-func _in(value any, values any) bool {
-	if value == nil || values == nil {
-		return false
-	}
-
-	if typing.IsString(values) {
-		return strings.Contains(values.(string), value.(string))
-	}
-
-	if !typing.IsSlice(values) {
-		return false
-	}
-
-	for _, element := range values.([]any) {
-		if typing.IsSlice(element) {
-			if _inRange(value, element) {
-				return true
-			}
-
-			continue
-		}
-
-		if typing.IsNumber(value) {
-			if typing.ToNumber(element) == value {
-				return true
-			}
-
-			continue
-		}
-
-		if element == value {
-			return true
-		}
-	}
-
-	return false
-}
-
-func merge(values any, level int8) any {
-	result := make([]any, 0)
-
-	if typing.IsPrimitive(values) || level > 1 {
-		return append(result, values)
-	}
-
-	if typing.IsSlice(values) {
-		for _, value := range values.([]any) {
-			_values := merge(value, level+1).([]any)
-
-			result = append(result, _values...)
-		}
-	}
-
-	return result
-}
-
-func missing(values, data any) any {
-	if typing.IsString(values) {
-		values = []any{values}
-	}
-
-	missing := make([]any, 0)
-
-	for _, _var := range values.([]any) {
-		_value := getVar(_var, data)
-
-		if _value == nil {
-			missing = append(missing, _var)
-		}
-	}
-
-	return missing
-}
-
-func missingSome(values, data any) any {
-	parsed := values.([]any)
-	number := int(typing.ToNumber(parsed[0]))
-	vars := parsed[1]
-
-	missing := make([]any, 0)
-	found := make([]any, 0)
-
-	for _, _var := range vars.([]any) {
-		_value := getVar(_var, data)
-
-		if _value == nil {
-			missing = append(missing, _var)
-		} else {
-			found = append(found, _var)
-		}
-	}
-
-	if number > len(found) {
-		return missing
-	}
-
-	return make([]any, 0)
-}
-
-func all(values, data any) any {
-	parsed := values.([]any)
-
-	var subject any
-
-	if typing.IsMap(parsed[0]) {
-		subject = apply(parsed[0], data)
-	}
-
-	if typing.IsSlice(parsed[0]) {
-		subject = parsed[0]
-	}
-
-	if !typing.IsTrue(subject) {
-		return false
-	}
-
-	for _, value := range subject.([]any) {
-		conditions := solveVars(parsed[1], value)
-		v := apply(conditions, value)
-
-		if !typing.IsTrue(v) {
-			return false
-		}
-	}
-
-	return true
-}
-
-func none(values, data any) any {
-	parsed := values.([]any)
-
-	var subject any
-
-	if typing.IsMap(parsed[0]) {
-		subject = apply(parsed[0], data)
-	}
-
-	if typing.IsSlice(parsed[0]) {
-		subject = parsed[0]
-	}
-
-	if !typing.IsTrue(subject) {
-		return true
-	}
-
-	conditions := solveVars(parsed[1], data)
-
-	for _, value := range subject.([]any) {
-		v := apply(conditions, value)
-
-		if typing.IsTrue(v) {
-			return false
-		}
-	}
-
-	return true
-}
-
-func some(values, data any) any {
-	parsed := values.([]any)
-
-	var subject any
-
-	if typing.IsMap(parsed[0]) {
-		subject = apply(parsed[0], data)
-	}
-
-	if typing.IsSlice(parsed[0]) {
-		subject = parsed[0]
-	}
-
-	if !typing.IsTrue(subject) {
-		return false
-	}
-
-	for _, value := range subject.([]any) {
-		v := apply(
-			solveVars(
-				solveVars(parsed[1], data),
-				value,
-			),
-			value,
-		)
-
-		if typing.IsTrue(v) {
-			return true
-		}
-	}
-
-	return false
-}
diff --git a/comp.go b/comp.go
index c5cd362..04e57f9 100644
--- a/comp.go
+++ b/comp.go
@@ -44,36 +44,3 @@ func equals(a, b any) bool {
 
 	return javascript.ToNumber(a) == javascript.ToNumber(b)
 }
-
-func between(operator string, values []any, data any) any {
-	a := parseValues(values[0], data)
-	b := parseValues(values[1], data)
-	c := parseValues(values[2], data)
-
-	if operator == "<" {
-		return less(a, b) && less(b, c)
-	}
-
-	if operator == "<=" {
-		return (less(a, b) || equals(a, b)) && (less(b, c) || equals(b, c))
-	}
-
-	if operator == ">=" {
-		return (less(c, b) || equals(c, b)) && (less(b, a) || equals(b, a))
-	}
-
-	return less(c, b) && less(b, a)
-}
-
-func _inRange(value any, values any) bool {
-	v := values.([]any)
-
-	i := v[0]
-	j := v[1]
-
-	if typing.IsNumber(value) {
-		return typing.ToNumber(value) >= typing.ToNumber(i) && typing.ToNumber(j) >= typing.ToNumber(value)
-	}
-
-	return typing.ToString(value) >= typing.ToString(i) && typing.ToString(j) >= typing.ToString(value)
-}
diff --git a/jsonlogic.go b/jsonlogic.go
index 2949420..75812e5 100644
--- a/jsonlogic.go
+++ b/jsonlogic.go
@@ -2,142 +2,416 @@ package jsonlogic
 
 import (
 	"encoding/json"
+	"fmt"
 	"io"
 	"strings"
 
+	"github.com/barkimedes/go-deepcopy"
+
 	"github.com/diegoholiveira/jsonlogic/v3/internal/typing"
 )
 
-// Apply reads a rule and data from `io.Reader`, applies the rule to the data
-// and writes the result to the provided writer. It returns an error if rule
-// processing or data handling fails.
-//
-// Parameters:
-//   - rule: io.Reader representing the transformation rule to be applied
-//   - data: io.Reader containing the input data to transform
-//   - result: io.Writer containing the transformed data
-//
-// Returns:
-//   - err: error if the transformation fails or if type assertions are invalid
-func Apply(rule, data io.Reader, result io.Writer) error {
-	if data == nil {
-		data = strings.NewReader("{}")
+type ErrInvalidOperator struct {
+	operator string
+}
+
+func (e ErrInvalidOperator) Error() string {
+	return fmt.Sprintf("The operator \"%s\" is not supported", e.operator)
+}
+
+func between(operator string, values []any, data any) any {
+	a := parseValues(values[0], data)
+	b := parseValues(values[1], data)
+	c := parseValues(values[2], data)
+
+	if operator == "<" {
+		return less(a, b) && less(b, c)
 	}
 
-	var _rule any
-	var _data any
+	if operator == "<=" {
+		return (less(a, b) || equals(a, b)) && (less(b, c) || equals(b, c))
+	}
 
-	decoder := json.NewDecoder(rule)
-	err := decoder.Decode(&_rule)
-	if err != nil {
-		return err
+	if operator == ">=" {
+		return (less(c, b) || equals(c, b)) && (less(b, a) || equals(b, a))
 	}
 
-	decoder = json.NewDecoder(data)
-	err = decoder.Decode(&_data)
-	if err != nil {
-		return err
+	return less(c, b) && less(b, a)
+}
+
+func unary(operator string, value any) any {
+	if operator == "+" || operator == "*" || operator == "/" {
+		return typing.ToNumber(value)
 	}
 
-	output, err := ApplyInterface(_rule, _data)
-	if err != nil {
-		return err
+	if operator == "-" {
+		return -1 * typing.ToNumber(value)
 	}
 
-	return json.NewEncoder(result).Encode(output)
+	if operator == "!!" {
+		return !unary("!", value).(bool)
+	}
+
+	if operator == "abs" {
+		return abs(value)
+	}
+
+	b := typing.IsTrue(value)
+
+	if operator == "!" {
+		return !b
+	}
+
+	return b
 }
 
-// ApplyRaw applies a validation rule to a JSON data input, both provided as raw JSON messages.
-// It processes the input data according to the provided rule and returns the transformed result.
-//
-// Parameters:
-//   - rule: json.RawMessage representing the transformation rule to be applied
-//   - data: json.RawMessage containing the input data to transform
-//
-// Returns:
-//   - output: json.RawMessage containing the transformed data
-//   - err: error if the transformation fails or if type assertions are invalid
-func ApplyRaw(rule, data json.RawMessage) (json.RawMessage, error) {
-	if data == nil {
-		data = json.RawMessage("{}")
+func _and(values, data any) any {
+	values = getValuesWithoutParsing(values, data)
+
+	var v float64
+
+	isBoolExpression := true
+
+	for _, value := range values.([]any) {
+		value = parseValues(value, data)
+		if typing.IsSlice(value) {
+			return value
+		}
+
+		if typing.IsBool(value) && !value.(bool) {
+			return false
+		}
+
+		if typing.IsString(value) && typing.ToString(value) == "" {
+			return value
+		}
+
+		if !typing.IsNumber(value) {
+			continue
+		}
+
+		isBoolExpression = false
+
+		_value := typing.ToNumber(value)
+
+		if _value > v {
+			v = _value
+		}
 	}
 
-	var _rule any
-	var _data any
+	if isBoolExpression {
+		return true
+	}
 
-	err := json.Unmarshal(rule, &_rule)
-	if err != nil {
-		return nil, err
+	return v
+}
+
+func _or(values, data any) any {
+	values = getValuesWithoutParsing(values, data)
+
+	for _, value := range values.([]any) {
+		parsed := parseValues(value, data)
+		if typing.IsTrue(parsed) {
+			return parsed
+		}
 	}
 
-	err = json.Unmarshal(data, &_data)
-	if err != nil {
-		return nil, err
+	return false
+}
+
+func _inRange(value any, values any) bool {
+	v := values.([]any)
+
+	i := v[0]
+	j := v[1]
+
+	if typing.IsNumber(value) {
+		return typing.ToNumber(value) >= typing.ToNumber(i) && typing.ToNumber(j) >= typing.ToNumber(value)
 	}
 
-	result, err := ApplyInterface(_rule, _data)
-	if err != nil {
-		return nil, err
+	return typing.ToString(value) >= typing.ToString(i) && typing.ToString(j) >= typing.ToString(value)
+}
+
+func _in(value any, values any) bool {
+	if value == nil || values == nil {
+		return false
 	}
 
-	return json.Marshal(&result)
+	if typing.IsString(values) {
+		return strings.Contains(values.(string), value.(string))
+	}
+
+	if !typing.IsSlice(values) {
+		return false
+	}
+
+	for _, element := range values.([]any) {
+		if typing.IsSlice(element) {
+			if _inRange(value, element) {
+				return true
+			}
+
+			continue
+		}
+
+		if typing.IsNumber(value) {
+			if typing.ToNumber(element) == value {
+				return true
+			}
+
+			continue
+		}
+
+		if element == value {
+			return true
+		}
+	}
+
+	return false
 }
 
-// ApplyInterface applies a transformation rule to input data using interface type assertions.
-// It processes the input data according to the provided rule and returns the transformed result.
-//
-// Parameters:
-//   - rule: interface{} representing the transformation rule to be applied
-//   - data: interface{} containing the input data to transform
-//
-// Returns:
-//   - output: interface{} containing the transformed data
-//   - err: error if the transformation fails or if type assertions are invalid
-func ApplyInterface(rule, data any) (output any, err error) {
-	defer func() {
-		if e := recover(); e != nil {
-			// fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
-			err = e.(error)
+func max(values any) any {
+	converted := values.([]any)
+	size := len(converted)
+	if size == 0 {
+		return nil
+	}
+
+	bigger := typing.ToNumber(converted[0])
+
+	for i := 1; i < size; i++ {
+		_n := typing.ToNumber(converted[i])
+		if _n > bigger {
+			bigger = _n
 		}
-	}()
+	}
 
-	if typing.IsMap(rule) {
-		return apply(rule, data), err
+	return bigger
+}
+
+func min(values any) any {
+	converted := values.([]any)
+	size := len(converted)
+	if size == 0 {
+		return nil
 	}
 
-	if typing.IsSlice(rule) {
-		var parsed []any
+	smallest := typing.ToNumber(converted[0])
 
-		for _, value := range rule.([]any) {
-			parsed = append(parsed, parseValues(value, data))
+	for i := 1; i < size; i++ {
+		_n := typing.ToNumber(converted[i])
+		if smallest > _n {
+			smallest = _n
 		}
+	}
 
-		return any(parsed), nil
+	return smallest
+}
+
+func merge(values any, level int8) any {
+	result := make([]any, 0)
+
+	if typing.IsPrimitive(values) || level > 1 {
+		return append(result, values)
 	}
 
-	return rule, err
+	if typing.IsSlice(values) {
+		for _, value := range values.([]any) {
+			_values := merge(value, level+1).([]any)
+
+			result = append(result, _values...)
+		}
+	}
+
+	return result
 }
 
-func GetJsonLogicWithSolvedVars(rule, data json.RawMessage) ([]byte, error) {
-	if data == nil {
-		data = json.RawMessage("{}")
+func conditional(values, data any) any {
+	if typing.IsPrimitive(values) {
+		return values
 	}
 
-	// parse rule and data from json.RawMessage to interface
-	var _rule any
-	var _data any
+	parsed := values.([]any)
 
-	err := json.Unmarshal(rule, &_rule)
-	if err != nil {
-		return nil, err
+	length := len(parsed)
+
+	if length == 0 {
+		return nil
 	}
 
-	err = json.Unmarshal(data, &_data)
+	for i := 0; i < length-1; i = i + 2 {
+		v := parsed[i]
+		if typing.IsMap(v) {
+			v = getVar(parsed[i], data)
+		}
+
+		if typing.IsTrue(v) {
+			return parseValues(parsed[i+1], data)
+		}
+	}
+
+	if length%2 == 1 {
+		return parsed[length-1]
+	}
+
+	return nil
+}
+
+func setProperty(value, data any) any {
+	_value := value.([]any)
+
+	object := _value[0]
+
+	if !typing.IsMap(object) {
+		return object
+	}
+
+	property := _value[1].(string)
+	modified, err := deepcopy.Anything(object)
 	if err != nil {
-		return nil, err
+		panic(err)
 	}
 
-	return solveVarsBackToJsonLogic(_rule, _data)
+	_modified := modified.(map[string]any)
+	_modified[property] = parseValues(_value[2], data)
+
+	return any(_modified)
+}
+
+func missing(values, data any) any {
+	if typing.IsString(values) {
+		values = []any{values}
+	}
+
+	missing := make([]any, 0)
+
+	for _, _var := range values.([]any) {
+		_value := getVar(_var, data)
+
+		if _value == nil {
+			missing = append(missing, _var)
+		}
+	}
+
+	return missing
+}
+
+func missingSome(values, data any) any {
+	parsed := values.([]any)
+	number := int(typing.ToNumber(parsed[0]))
+	vars := parsed[1]
+
+	missing := make([]any, 0)
+	found := make([]any, 0)
+
+	for _, _var := range vars.([]any) {
+		_value := getVar(_var, data)
+
+		if _value == nil {
+			missing = append(missing, _var)
+		} else {
+			found = append(found, _var)
+		}
+	}
+
+	if number > len(found) {
+		return missing
+	}
+
+	return make([]any, 0)
+}
+
+func all(values, data any) any {
+	parsed := values.([]any)
+
+	var subject any
+
+	if typing.IsMap(parsed[0]) {
+		subject = apply(parsed[0], data)
+	}
+
+	if typing.IsSlice(parsed[0]) {
+		subject = parsed[0]
+	}
+
+	if !typing.IsTrue(subject) {
+		return false
+	}
+
+	for _, value := range subject.([]any) {
+		conditions := solveVars(parsed[1], value)
+		v := apply(conditions, value)
+
+		if !typing.IsTrue(v) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func none(values, data any) any {
+	parsed := values.([]any)
+
+	var subject any
+
+	if typing.IsMap(parsed[0]) {
+		subject = apply(parsed[0], data)
+	}
+
+	if typing.IsSlice(parsed[0]) {
+		subject = parsed[0]
+	}
+
+	if !typing.IsTrue(subject) {
+		return true
+	}
+
+	conditions := solveVars(parsed[1], data)
+
+	for _, value := range subject.([]any) {
+		v := apply(conditions, value)
+
+		if typing.IsTrue(v) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func some(values, data any) any {
+	parsed := values.([]any)
+
+	var subject any
+
+	if typing.IsMap(parsed[0]) {
+		subject = apply(parsed[0], data)
+	}
+
+	if typing.IsSlice(parsed[0]) {
+		subject = parsed[0]
+	}
+
+	if !typing.IsTrue(subject) {
+		return false
+	}
+
+	for _, value := range subject.([]any) {
+		v := apply(
+			solveVars(
+				solveVars(parsed[1], data),
+				value,
+			),
+			value,
+		)
+
+		if typing.IsTrue(v) {
+			return true
+		}
+	}
+
+	return false
 }
 
 func parseValues(values, data any) any {
@@ -218,3 +492,110 @@ func apply(rules, data any) any {
 	// an empty-map rule should return an empty-map
 	return make(map[string]any)
 }
+
+// Apply read the rule and it's data from io.Reader, executes it
+// and write back a JSON into an io.Writer result
+func Apply(rule, data io.Reader, result io.Writer) error {
+	if data == nil {
+		data = strings.NewReader("{}")
+	}
+
+	var _rule any
+	var _data any
+
+	decoder := json.NewDecoder(rule)
+	err := decoder.Decode(&_rule)
+	if err != nil {
+		return err
+	}
+
+	decoder = json.NewDecoder(data)
+	err = decoder.Decode(&_data)
+	if err != nil {
+		return err
+	}
+
+	output, err := ApplyInterface(_rule, _data)
+	if err != nil {
+		return err
+	}
+
+	return json.NewEncoder(result).Encode(output)
+}
+
+func GetJsonLogicWithSolvedVars(rule, data json.RawMessage) ([]byte, error) {
+	if data == nil {
+		data = json.RawMessage("{}")
+	}
+
+	// parse rule and data from json.RawMessage to interface
+	var _rule any
+	var _data any
+
+	err := json.Unmarshal(rule, &_rule)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(data, &_data)
+	if err != nil {
+		return nil, err
+	}
+
+	return solveVarsBackToJsonLogic(_rule, _data)
+}
+
+// ApplyRaw receives a rule and data as json.RawMessage and returns the result
+// of the rule applied to the data.
+func ApplyRaw(rule, data json.RawMessage) (json.RawMessage, error) {
+	if data == nil {
+		data = json.RawMessage("{}")
+	}
+
+	var _rule any
+	var _data any
+
+	err := json.Unmarshal(rule, &_rule)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(data, &_data)
+	if err != nil {
+		return nil, err
+	}
+
+	result, err := ApplyInterface(_rule, _data)
+	if err != nil {
+		return nil, err
+	}
+
+	return json.Marshal(&result)
+}
+
+// ApplyInterface receives a rule and data as any and returns the result
+// of the rule applied to the data.
+func ApplyInterface(rule, data any) (output any, err error) {
+	defer func() {
+		if e := recover(); e != nil {
+			// fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
+			err = e.(error)
+		}
+	}()
+
+	if typing.IsMap(rule) {
+		return apply(rule, data), err
+	}
+
+	if typing.IsSlice(rule) {
+		var parsed []any
+
+		for _, value := range rule.([]any) {
+			parsed = append(parsed, parseValues(value, data))
+		}
+
+		return any(parsed), nil
+	}
+
+	return rule, err
+}
diff --git a/logic.go b/logic.go
deleted file mode 100644
index 9d22e2b..0000000
--- a/logic.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package jsonlogic
-
-import "github.com/diegoholiveira/jsonlogic/v3/internal/typing"
-
-func _and(values, data any) any {
-	values = getValuesWithoutParsing(values, data)
-
-	var v float64
-
-	isBoolExpression := true
-
-	for _, value := range values.([]any) {
-		value = parseValues(value, data)
-		if typing.IsSlice(value) {
-			return value
-		}
-
-		if typing.IsBool(value) && !value.(bool) {
-			return false
-		}
-
-		if typing.IsString(value) && typing.ToString(value) == "" {
-			return value
-		}
-
-		if !typing.IsNumber(value) {
-			continue
-		}
-
-		isBoolExpression = false
-
-		_value := typing.ToNumber(value)
-
-		if _value > v {
-			v = _value
-		}
-	}
-
-	if isBoolExpression {
-		return true
-	}
-
-	return v
-}
-
-func _or(values, data any) any {
-	values = getValuesWithoutParsing(values, data)
-
-	for _, value := range values.([]any) {
-		parsed := parseValues(value, data)
-		if typing.IsTrue(parsed) {
-			return parsed
-		}
-	}
-
-	return false
-}
-
-func conditional(values, data any) any {
-	if typing.IsPrimitive(values) {
-		return values
-	}
-
-	parsed := values.([]any)
-
-	length := len(parsed)
-
-	if length == 0 {
-		return nil
-	}
-
-	for i := 0; i < length-1; i = i + 2 {
-		v := parsed[i]
-		if typing.IsMap(v) {
-			v = getVar(parsed[i], data)
-		}
-
-		if typing.IsTrue(v) {
-			return parseValues(parsed[i+1], data)
-		}
-	}
-
-	if length%2 == 1 {
-		return parsed[length-1]
-	}
-
-	return nil
-}
-
-func unary(operator string, value any) any {
-	if operator == "+" || operator == "*" || operator == "/" {
-		return typing.ToNumber(value)
-	}
-
-	if operator == "-" {
-		return -1 * typing.ToNumber(value)
-	}
-
-	if operator == "!!" {
-		return !unary("!", value).(bool)
-	}
-
-	if operator == "abs" {
-		return abs(value)
-	}
-
-	b := typing.IsTrue(value)
-
-	if operator == "!" {
-		return !b
-	}
-
-	return b
-}
diff --git a/math.go b/math.go
index 635fc22..f835705 100644
--- a/math.go
+++ b/math.go
@@ -68,41 +68,3 @@ func div(values any) any {
 
 	return sum
 }
-
-func max(values any) any {
-	converted := values.([]any)
-	size := len(converted)
-	if size == 0 {
-		return nil
-	}
-
-	bigger := typing.ToNumber(converted[0])
-
-	for i := 1; i < size; i++ {
-		_n := typing.ToNumber(converted[i])
-		if _n > bigger {
-			bigger = _n
-		}
-	}
-
-	return bigger
-}
-
-func min(values any) any {
-	converted := values.([]any)
-	size := len(converted)
-	if size == 0 {
-		return nil
-	}
-
-	smallest := typing.ToNumber(converted[0])
-
-	for i := 1; i < size; i++ {
-		_n := typing.ToNumber(converted[i])
-		if smallest > _n {
-			smallest = _n
-		}
-	}
-
-	return smallest
-}
diff --git a/operation.go b/operation.go
index 3daa71c..4ac31c4 100644
--- a/operation.go
+++ b/operation.go
@@ -1,20 +1,10 @@
 package jsonlogic
 
 import (
-	"fmt"
-
 	"github.com/diegoholiveira/jsonlogic/v3/internal/javascript"
 	"github.com/diegoholiveira/jsonlogic/v3/internal/typing"
 )
 
-type ErrInvalidOperator struct {
-	operator string
-}
-
-func (e ErrInvalidOperator) Error() string {
-	return fmt.Sprintf("The operator \"%s\" is not supported", e.operator)
-}
-
 // customOperators holds custom operators
 var customOperators = make(map[string]func(values, data any) (result any))
 
diff --git a/vars.go b/vars.go
index 407e7a3..c072fb6 100644
--- a/vars.go
+++ b/vars.go
@@ -5,8 +5,6 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/barkimedes/go-deepcopy"
-
 	"github.com/diegoholiveira/jsonlogic/v3/internal/typing"
 )
 
@@ -91,35 +89,29 @@ func getVar(value, data any) any {
 
 	parts := strings.Split(value.(string), ".")
 
-	var _value any
+	var _value any = data
 
 	for _, part := range parts {
 		if part == "" {
 			continue
 		}
 
-		if typing.IsMap(data) {
-			_value = data.(map[string]any)[part]
-		}
-
-		if typing.IsSlice(data) {
+		if typing.IsMap(_value) {
+			_value = _value.(map[string]any)[part]
+		} else if typing.IsSlice(_value) {
 			pos := int(typing.ToNumber(part))
-			container := data.([]any)
+			container := _value.([]any)
 			if pos >= len(container) {
 				return _default
 			}
 			_value = container[pos]
+		} else {
+			return _default
 		}
 
 		if _value == nil {
 			return _default
 		}
-
-		if typing.IsPrimitive(_value) {
-			continue
-		}
-
-		data = _value
 	}
 
 	return _value
@@ -149,24 +141,3 @@ func solveVarsBackToJsonLogic(rule, data any) (json.RawMessage, error) {
 
 	return []byte(resultEscaped), nil
 }
-
-func setProperty(value, data any) any {
-	_value := value.([]any)
-
-	object := _value[0]
-
-	if !typing.IsMap(object) {
-		return object
-	}
-
-	property := _value[1].(string)
-	modified, err := deepcopy.Anything(object)
-	if err != nil {
-		panic(err)
-	}
-
-	_modified := modified.(map[string]any)
-	_modified[property] = parseValues(_value[2], data)
-
-	return any(_modified)
-}


Test patch:
diff --git a/issues_test.go b/issues_test.go
index 2604ba6..85b6602 100644
--- a/issues_test.go
+++ b/issues_test.go
@@ -347,3 +347,17 @@ func TestIssue98(t *testing.T) {
 	expected := `true`
 	assert.JSONEq(t, expected, result.String())
 }
+
+func TestIssue110(t *testing.T) {
+	logic := strings.NewReader(`{ "map":[{"var": "arr"},{"var":["xxx", "default"]}]}`)
+	data := strings.NewReader(`{"arr": [{"xxx": "111","yyy": "222"},{"xxx": "333","yyy": "444"}]}`)
+
+	var result bytes.Buffer
+	err := jsonlogic.Apply(logic, data, &result)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := `["111","333"]`
+	assert.JSONEq(t, expected, result.String())
+}