Skip to content

Commit 7332aad

Browse files
committed
Update AdvancedQueryBuilder.java
1 parent d9e97f2 commit 7332aad

1 file changed

Lines changed: 44 additions & 62 deletions

File tree

apps/modernization-api/src/main/java/gov/cdc/nbs/report/AdvancedQueryBuilder.java

Lines changed: 44 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -39,32 +39,41 @@ public AdvancedQueryBuilder(List<FilterValue> filterValues) {
3939
}
4040

4141
public AdvancedQuery.RuleGroup build() {
42-
AdvancedQuery.Rule firstRule = null;
43-
ReportConstants.QueryCombinators firstCombinator = null;
42+
AdvancedQuery.RuleGroup ruleGroup = buildRuleGroup(ReportConstants.QueryCombinators.and, null);
4443

45-
// Iterate through FilterValues until we find the first OPERATOR
46-
while (hasNext()) {
47-
FilterValue filterValue = peek();
48-
if (filterValue.getValueType().equals("CLAUSE")) {
49-
firstRule = buildClause(filterValue);
50-
} else if (filterValue.getValueType().equals("OPERATOR")) {
51-
if (filterValue.getOperator().equals("and") || filterValue.getOperator().equals("or")) {
52-
firstCombinator = ReportConstants.QueryCombinators.valueOf(filterValue.getOperator());
53-
break;
54-
}
55-
}
56-
advance();
57-
}
44+
return unwrapRuleGroup(ruleGroup);
45+
}
5846

59-
// If we didn't find an OPERATOR, default to 'AND' combinator for a single rule
60-
if (firstCombinator == null) {
61-
firstCombinator = ReportConstants.QueryCombinators.and;
47+
private AdvancedQuery.RuleGroup unwrapRuleGroup(AdvancedQuery.RuleGroup ruleGroup) {
48+
// If a RuleGroup has only one Rule, and it's also a RuleGroup
49+
if (ruleGroup.rules().size() == 1
50+
&& ruleGroup.rules().getFirst() instanceof AdvancedQuery.RuleGroup) {
51+
52+
// We can do away with the outer RuleGroup
53+
return unwrapRuleGroup((AdvancedQuery.RuleGroup) ruleGroup.rules().getFirst());
54+
} else if (ruleGroup.rules().size() > 1) {
55+
return new AdvancedQuery.RuleGroup(
56+
ruleGroup.id(),
57+
ruleGroup.combinator(),
58+
ruleGroup.rules().stream()
59+
.map(
60+
rule -> {
61+
// If a RuleGroup's rule is a RuleGroup, and it has only one Rule
62+
if (rule instanceof AdvancedQuery.RuleGroup nestedRuleGroup) {
63+
if ((nestedRuleGroup.rules().size() == 1
64+
&& nestedRuleGroup.rules().getFirst() instanceof AdvancedQuery.Rule)) {
65+
// Bypass the nested RuleGroup and attach the inner Rule to the outer
66+
// RuleGroup
67+
return nestedRuleGroup.rules().getFirst();
68+
} else {
69+
return unwrapRuleGroup(nestedRuleGroup);
70+
}
71+
} else {
72+
return rule;
73+
}
74+
})
75+
.toList());
6276
}
63-
64-
// Then build the root RuleGroup from said OPERATOR and corresponding rule
65-
AdvancedQuery.RuleGroup ruleGroup = buildRuleGroup(firstCombinator, firstRule);
66-
67-
System.out.println(ruleGroup);
6877
return ruleGroup;
6978
}
7079

@@ -76,7 +85,6 @@ private AdvancedQuery.RuleGroup buildRuleGroup(
7685
}
7786

7887
AdvancedQuery.RuleGroup ruleGroup = null;
79-
int nestDepth = 0;
8088
boolean terminated = false;
8189

8290
while (hasNext()) {
@@ -92,29 +100,15 @@ private AdvancedQuery.RuleGroup buildRuleGroup(
92100
switch (filterValue.getOperator()) {
93101
case "or":
94102
if (combinator.equals(ReportConstants.QueryCombinators.and)) {
95-
// If going directly from an 'AND' group to an 'OR' group, without parens
96-
if (nestDepth == 0) {
97-
// We terminate the current 'AND' group
98-
terminated = true;
99-
AdvancedQuery.RuleGroup andGroup =
100-
new AdvancedQuery.RuleGroup(
101-
UUID.randomUUID().toString(),
102-
ReportConstants.QueryCombinators.and,
103-
rules);
104-
105-
// And add it as a rule to the new 'OR' group, which we then build
106-
ruleGroup = buildRuleGroup(ReportConstants.QueryCombinators.or, andGroup);
107-
108-
// If going from an 'AND' group to an 'OR' group WITHIN inner parens
109-
} else {
110-
// We just build the 'OR' group, starting from the previous FilterValue
111-
AdvancedQuery firstOrRule = rules.removeLast();
112-
AdvancedQuery.RuleGroup orGroup =
113-
buildRuleGroup(ReportConstants.QueryCombinators.or, firstOrRule);
114-
115-
// And add it to the existing list of 'AND' group rules
116-
rules.add(orGroup);
117-
}
103+
// If going directly from an 'AND' group to an 'OR' group, terminate the current
104+
// 'AND' group
105+
terminated = true;
106+
AdvancedQuery.RuleGroup andGroup =
107+
new AdvancedQuery.RuleGroup(
108+
UUID.randomUUID().toString(), ReportConstants.QueryCombinators.and, rules);
109+
110+
// And add it as a rule to the new 'OR' group, which we then build
111+
ruleGroup = buildRuleGroup(ReportConstants.QueryCombinators.or, andGroup);
118112
}
119113
break;
120114
case "and":
@@ -137,20 +131,12 @@ private AdvancedQuery.RuleGroup buildRuleGroup(
137131
"Cannot follow a closing parenthesis with an open parenthesis without an OPERATOR in between",
138132
filterValue));
139133
}
140-
nestDepth++;
134+
advance();
135+
rules.add(buildRuleGroup(ReportConstants.QueryCombinators.and, null));
141136
break;
142137
case ")":
143138
// If we encounter a closed parenthesis without any nesting, terminate the rule group
144-
if (nestDepth == 0) {
145-
terminated = true;
146-
} else {
147-
nestDepth--;
148-
}
149-
150-
if (nestDepth < 0) {
151-
queryErrors.add(
152-
new AdvancedQueryException("Too many closing parentheses", filterValue));
153-
}
139+
terminated = true;
154140
break;
155141
default:
156142
queryErrors.add(
@@ -170,10 +156,6 @@ private AdvancedQuery.RuleGroup buildRuleGroup(
170156
}
171157
}
172158

173-
if (nestDepth != 0) {
174-
queryErrors.add(new AdvancedQueryException("Mismatched parentheses"));
175-
}
176-
177159
if (!queryErrors.isEmpty()) {
178160
// TODO: What exactly do we wanna do here? Should we still return the partially built
179161
// ruleGroup

0 commit comments

Comments
 (0)