Skip to content

Commit

Permalink
cache the expensive placeholder lookaround results so that the templa…
Browse files Browse the repository at this point in the history
…te() will be cheaper when used repeatedly.
  • Loading branch information
fluentfuture committed Nov 7, 2024
1 parent b61fdf7 commit 5b94e6c
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions mug-guava/src/main/java/com/google/mu/safesql/SafeSql.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import java.util.stream.Collector;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -387,6 +389,7 @@ public static SafeSql when(
* <p>The returned template is immutable and thread safe.
*/
public static Template<SafeSql> template(@CompileTimeConstant String template) {
ConcurrentMap<String, Boolean> placeholderSurroundings = new ConcurrentHashMap<>();
return StringFormat.template(template, (fragments, placeholders) -> {
Deque<String> texts = new ArrayDeque<>(fragments);
Builder builder = new Builder();
Expand All @@ -406,7 +409,7 @@ void writePlaceholder(Substring.Match placeholder, Object value) {
Iterator<?> elements = ((Iterable<?>) value).iterator();
checkArgument(elements.hasNext(), "%s cannot be empty list", placeholder);
if (placeholder.isImmediatelyBetween("'", "'")
&& matchesPattern("IN ('", placeholder, "')")
&& lookaround("IN ('", placeholder, "')")
&& appendBeforeQuotedPlaceholder("'", placeholder, "'")) {
builder.addSubQuery(
eachPlaceholderValue(placeholder, elements)
Expand All @@ -421,7 +424,7 @@ && appendBeforeQuotedPlaceholder("'", placeholder, "'")) {
eachPlaceholderValue(placeholder, elements)
.mapToObj(SafeSql::mustBeIdentifier)
.collect(Collectors.joining("`, `")));
} else if (matchesPattern("IN (", placeholder, ")")) {
} else if (lookaround("IN (", placeholder, ")")) {
builder.addSubQuery(
eachPlaceholderValue(placeholder, elements)
.mapToObj(SafeSql::subqueryOrParameter)
Expand Down Expand Up @@ -464,6 +467,13 @@ private boolean appendBeforeQuotedPlaceholder(
}
return quoted;
}

private boolean lookaround(
String leftPattern, Substring.Match placeholder, String rightPattern) {
return placeholderSurroundings.computeIfAbsent(
leftPattern + "{" + placeholder.index() + "}" + rightPattern,
k -> matchesPattern(leftPattern, placeholder, rightPattern));
}
}
placeholders.forEachOrdered(new SqlWriter()::writePlaceholder);
builder.appendSql(texts.pop());
Expand Down

0 comments on commit 5b94e6c

Please # to comment.