Skip to content

Commit dbd8400

Browse files
authored
Refactor global variable management to separate global and context-specific variables. (#216)
When clearing variables between executions, only clear the context variables.
1 parent 3bc5694 commit dbd8400

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

expression-src/main/src/interpreter/Environment.cls

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,25 @@ public with sharing class Environment {
1414
return allVariables;
1515
}
1616

17+
/**
18+
* @description A map of global variables that can be accessed from any formula.
19+
* These should always yield the same value regardless of the context in which they are used.
20+
*/
1721
private static final Map<String, Object> GLOBAL_VARIABLES = new Map<String, Object>();
1822

23+
/**
24+
* @description A map of global context variables that can be accessed from any formula.
25+
* These are specific to the context in which they are used, and are reset after each evaluation.
26+
*/
27+
private static final Map<String, Object> GLOBAL_CONTEXT_VARIABLES = new Map<String, Object>();
28+
29+
private static Map<String, Object> getAllGlobalVariables() {
30+
Map<String, Object> allGlobalVariables = new Map<String, Object>();
31+
allGlobalVariables.putAll(GLOBAL_VARIABLES);
32+
allGlobalVariables.putAll(GLOBAL_CONTEXT_VARIABLES);
33+
return allGlobalVariables;
34+
}
35+
1936
static {
2037
GLOBAL_VARIABLES.put('$label', new CustomLabelVariableResolver.CustomLabelResolverWrapper());
2138
GLOBAL_VARIABLES.put('$custommetadata', new CustomMetadataVariableResolver.CmtApiName());
@@ -33,11 +50,11 @@ public with sharing class Environment {
3350

3451
public static void addGlobalVariable(String name, Object value) {
3552
// Check that the name has not already been declared
36-
if (GLOBAL_VARIABLES.containsKey(name.toLowerCase())) {
53+
if (GLOBAL_CONTEXT_VARIABLES.containsKey(name.toLowerCase())) {
3754
throw new EnvironmentException('Variable or function with name ' + name + ' already exists');
3855
}
3956

40-
GLOBAL_VARIABLES.put(name.toLowerCase(), value);
57+
GLOBAL_CONTEXT_VARIABLES.put(name.toLowerCase(), value);
4158
}
4259

4360
public Boolean hasFunction(String functionName) {
@@ -53,7 +70,7 @@ public with sharing class Environment {
5370
}
5471

5572
// Otherwise, look in the global variables
56-
return (Expr.FunctionDeclaration)GLOBAL_VARIABLES.get(functionName.toLowerCase());
73+
return (Expr.FunctionDeclaration)GLOBAL_CONTEXT_VARIABLES.get(functionName.toLowerCase());
5774
}
5875

5976
/**
@@ -64,7 +81,7 @@ public with sharing class Environment {
6481
*/
6582
public static void addGlobalContextVariable(String name, Object value) {
6683
String prefixedName = '@' + name;
67-
GLOBAL_VARIABLES.put(prefixedName.toLowerCase(), value);
84+
GLOBAL_CONTEXT_VARIABLES.put(prefixedName.toLowerCase(), value);
6885
}
6986

7087
public Environment() {}
@@ -89,7 +106,7 @@ public with sharing class Environment {
89106
public Boolean contains(String field) {
90107
String lowerCaseField = field.toLowerCase();
91108

92-
if (getVariables().containsKey(lowerCaseField) || GLOBAL_VARIABLES.containsKey(lowerCaseField)) {
109+
if (getVariables().containsKey(lowerCaseField) || getAllGlobalVariables().containsKey(lowerCaseField)) {
93110
return true;
94111
}
95112

@@ -135,8 +152,9 @@ public with sharing class Environment {
135152
}
136153

137154
// Look in global variables
138-
if (GLOBAL_VARIABLES.containsKey(lowerCaseField)) {
139-
return GLOBAL_VARIABLES.get(lowerCaseField);
155+
Map<String, Object> allGlobalVariables = getAllGlobalVariables();
156+
if (allGlobalVariables.containsKey(lowerCaseField)) {
157+
return allGlobalVariables.get(lowerCaseField);
140158
}
141159

142160
if (getContext() == null) {
@@ -180,7 +198,7 @@ public with sharing class Environment {
180198

181199
public class ClearContext implements EvaluatorEventListener {
182200
public Map<String, Object> handle(EvaluatorEvent event) {
183-
GLOBAL_VARIABLES.clear();
201+
GLOBAL_CONTEXT_VARIABLES.clear();
184202
return null;
185203
}
186204
}

expression-src/spec/language/functions/FunctionDeclarationTest.cls

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,18 @@ private class FunctionDeclarationTest {
221221
Assert.fail('Should be able to run the evaluator multiple times: ' + e.getMessage());
222222
}
223223
}
224+
225+
@IsTest
226+
static void canUseGlobalVariablesWhenRunningEvaluatorMultipleTimes() {
227+
insert new Account(Name = 'ACME');
228+
229+
String expression = '$User.name';
230+
231+
try {
232+
Evaluator.run(expression);
233+
Evaluator.run(expression);
234+
} catch (Exception e) {
235+
Assert.fail('Should be able to run the evaluator multiple times: ' + e.getMessage());
236+
}
237+
}
224238
}

0 commit comments

Comments
 (0)