Skip to content

Commit

Permalink
Merge pull request #1 from mgrand/unbracketed-vars
Browse files Browse the repository at this point in the history
Unbracketed vars
  • Loading branch information
mgrand authored Oct 20, 2019
2 parents 32dc6a0 + e83392c commit d4cb876
Show file tree
Hide file tree
Showing 10 changed files with 346 additions and 132 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,7 @@ slf4j at <https://www.slf4j.org/manual.html>

## Roadmap
This is a list of planned future features:
* Availability of a pre-compiled jar in the Maven Central repository.
* Syntax for specifying explicit formatters/datatypes of simleyVars.
* Support for nested smileyVars brackets.
* Built-in support for additional datatypes:
* BitSet
* TimeDuration
Expand All @@ -240,7 +239,8 @@ This is a list of planned future features:
## Appendix: smileyVars Syntax

The EBNF grammar below describes the syntax of smileyVars. You can also
view it as a [syntax/railroad diagram](file:documentation/sv-grammar.xhtml)
view it as a [syntax/railroad diagram]
(https://gitcdn.link/repo/mgrand/smileyVars/master/documentation/sv-grammar.xhtml)
<small>(created using <https://www.bottlecaps.de/rr/ui>)</small>.


Expand Down
4 changes: 2 additions & 2 deletions documentation/smilieyVars.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
template_body ::= (sql_text | bracketed_text)*

sql_text ::= (other_char | quoted_string | quoted_identifier | comment | '(' [^:] )*
sql_text ::= (other_char | ":" var ( ':' type )? | quoted_string | quoted_identifier | comment | '(' [^:] )*

quoted_string ::= ansi_quoted_string | postgresql_escape_string | postgresql_dollar_string | oracle_delimited_string

Expand All @@ -24,7 +24,7 @@ oracle_delimited_string ::= [Qq] "'" ( "(" ([^)] | ")" [^'])* ")"

quoted_identifier ::= '"' ( [^"] | '"' '"' )* '"'

other_char ::= [^'"(]
other_char ::= [^'"(:]
comment ::= line_comment | block_comment

Expand Down
68 changes: 40 additions & 28 deletions documentation/sv-grammar.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
<div><a href="#template_body" title="template_body">template_body</a></div>
<div>         ::= ( <a href="#sql_text" title="sql_text">sql_text</a> | <a href="#bracketed_text" title="bracketed_text">bracketed_text</a> )*</div></code></div>
</p>
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">no references</p><br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><a name="sql_text">sql_text:</a></p><svg xmlns="http://www.w3.org/2000/svg" width="307" height="245">
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">no references</p><br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><a name="sql_text">sql_text:</a></p><svg xmlns="http://www.w3.org/2000/svg" width="415" height="321">
<defs>
<style type="text/css">
@namespace "http://www.w3.org/2000/svg";
Expand Down Expand Up @@ -296,26 +296,36 @@
<polygon points="17 33 9 29 9 37"/><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#other_char" xlink:title="other_char">
<rect x="91" y="19" width="88" height="32"/>
<rect x="89" y="17" width="88" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="37">other_char</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#quoted_string" xlink:title="quoted_string">
<rect x="91" y="63" width="108" height="32"/>
<rect x="89" y="61" width="108" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="81">quoted_string</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#quoted_identifier" xlink:title="quoted_identifier">
<rect x="91" y="107" width="128" height="32"/>
<rect x="89" y="105" width="128" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="125">quoted_identifier</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#comment" xlink:title="comment">
<rect x="91" y="151" width="78" height="32"/>
<rect x="89" y="149" width="78" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="169">comment</text></a><rect x="91" y="195" width="26" height="32" rx="10"/>
<rect x="89" y="193" width="26" height="32" class="terminal" rx="10"/>
<text class="terminal" x="99" y="213">(</text>
<polygon points="137 211 144 195 186 195 193 211 186 227 144 227"/>
<polygon points="135 209 142 193 184 193 191 209 184 225 142 225" class="regexp"/>
<text class="regexp" x="150" y="213">[^:]</text>
<path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 33 h2 m60 0 h10 m88 0 h10 m0 0 h40 m-168 0 h20 m148 0 h20 m-188 0 q10 0 10 10 m168 0 q0 -10 10 -10 m-178 10 v24 m168 0 v-24 m-168 24 q0 10 10 10 m148 0 q10 0 10 -10 m-158 10 h10 m108 0 h10 m0 0 h20 m-158 -10 v20 m168 0 v-20 m-168 20 v24 m168 0 v-24 m-168 24 q0 10 10 10 m148 0 q10 0 10 -10 m-158 10 h10 m128 0 h10 m-158 -10 v20 m168 0 v-20 m-168 20 v24 m168 0 v-24 m-168 24 q0 10 10 10 m148 0 q10 0 10 -10 m-158 10 h10 m78 0 h10 m0 0 h50 m-158 -10 v20 m168 0 v-20 m-168 20 v24 m168 0 v-24 m-168 24 q0 10 10 10 m148 0 q10 0 10 -10 m-158 10 h10 m26 0 h10 m0 0 h10 m56 0 h10 m0 0 h26 m-188 -176 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m188 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-188 0 h10 m0 0 h178 m-228 32 h20 m228 0 h20 m-268 0 q10 0 10 10 m248 0 q0 -10 10 -10 m-258 10 v190 m248 0 v-190 m-248 190 q0 10 10 10 m228 0 q10 0 10 -10 m-238 10 h10 m0 0 h218 m23 -210 h-3"/>
<polygon points="297 33 305 29 305 37"/>
<polygon points="297 33 289 29 289 37"/></svg><p xmlns:xhtml="http://www.w3.org/1999/xhtml">
<text class="nonterminal" x="99" y="37">other_char</text></a><rect x="91" y="63" width="24" height="32" rx="10"/>
<rect x="89" y="61" width="24" height="32" class="terminal" rx="10"/>
<text class="terminal" x="99" y="81">:</text><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#var" xlink:title="var">
<rect x="135" y="63" width="40" height="32"/>
<rect x="133" y="61" width="40" height="32" class="nonterminal"/>
<text class="nonterminal" x="143" y="81">var</text></a><rect x="215" y="95" width="24" height="32" rx="10"/>
<rect x="213" y="93" width="24" height="32" class="terminal" rx="10"/>
<text class="terminal" x="223" y="113">:</text><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#type" xlink:title="type">
<rect x="259" y="95" width="48" height="32"/>
<rect x="257" y="93" width="48" height="32" class="nonterminal"/>
<text class="nonterminal" x="267" y="113">type</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#quoted_string" xlink:title="quoted_string">
<rect x="91" y="139" width="108" height="32"/>
<rect x="89" y="137" width="108" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="157">quoted_string</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#quoted_identifier" xlink:title="quoted_identifier">
<rect x="91" y="183" width="128" height="32"/>
<rect x="89" y="181" width="128" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="201">quoted_identifier</text></a><a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#comment" xlink:title="comment">
<rect x="91" y="227" width="78" height="32"/>
<rect x="89" y="225" width="78" height="32" class="nonterminal"/>
<text class="nonterminal" x="99" y="245">comment</text></a><rect x="91" y="271" width="26" height="32" rx="10"/>
<rect x="89" y="269" width="26" height="32" class="terminal" rx="10"/>
<text class="terminal" x="99" y="289">(</text>
<polygon points="137 287 144 271 186 271 193 287 186 303 144 303"/>
<polygon points="135 285 142 269 184 269 191 285 184 301 142 301" class="regexp"/>
<text class="regexp" x="150" y="289">[^:]</text>
<path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 33 h2 m60 0 h10 m88 0 h10 m0 0 h148 m-276 0 h20 m256 0 h20 m-296 0 q10 0 10 10 m276 0 q0 -10 10 -10 m-286 10 v24 m276 0 v-24 m-276 24 q0 10 10 10 m256 0 q10 0 10 -10 m-266 10 h10 m24 0 h10 m0 0 h10 m40 0 h10 m20 0 h10 m0 0 h102 m-132 0 h20 m112 0 h20 m-152 0 q10 0 10 10 m132 0 q0 -10 10 -10 m-142 10 v12 m132 0 v-12 m-132 12 q0 10 10 10 m112 0 q10 0 10 -10 m-122 10 h10 m24 0 h10 m0 0 h10 m48 0 h10 m-246 -42 v20 m276 0 v-20 m-276 20 v56 m276 0 v-56 m-276 56 q0 10 10 10 m256 0 q10 0 10 -10 m-266 10 h10 m108 0 h10 m0 0 h128 m-266 -10 v20 m276 0 v-20 m-276 20 v24 m276 0 v-24 m-276 24 q0 10 10 10 m256 0 q10 0 10 -10 m-266 10 h10 m128 0 h10 m0 0 h108 m-266 -10 v20 m276 0 v-20 m-276 20 v24 m276 0 v-24 m-276 24 q0 10 10 10 m256 0 q10 0 10 -10 m-266 10 h10 m78 0 h10 m0 0 h158 m-266 -10 v20 m276 0 v-20 m-276 20 v24 m276 0 v-24 m-276 24 q0 10 10 10 m256 0 q10 0 10 -10 m-266 10 h10 m26 0 h10 m0 0 h10 m56 0 h10 m0 0 h134 m-296 -252 l20 0 m-1 0 q-9 0 -9 -10 l0 -12 q0 -10 10 -10 m296 32 l20 0 m-20 0 q10 0 10 -10 l0 -12 q0 -10 -10 -10 m-296 0 h10 m0 0 h286 m-336 32 h20 m336 0 h20 m-376 0 q10 0 10 10 m356 0 q0 -10 10 -10 m-366 10 v266 m356 0 v-266 m-356 266 q0 10 10 10 m336 0 q10 0 10 -10 m-346 10 h10 m0 0 h326 m23 -286 h-3"/>
<polygon points="405 33 413 29 413 37"/>
<polygon points="405 33 397 29 397 37"/></svg><p xmlns:xhtml="http://www.w3.org/1999/xhtml">
<div class="ebnf"><code>
<div><a href="#sql_text" title="sql_text">sql_text</a> ::= ( <a href="#other_char" title="other_char">other_char</a> | <a href="#quoted_string" title="quoted_string">quoted_string</a> | <a href="#quoted_identifier" title="quoted_identifier">quoted_identifier</a> | <a href="#comment" title="comment">comment</a> | '(' [^:] )*</div></code></div>
<div><a href="#sql_text" title="sql_text">sql_text</a> ::= ( <a href="#other_char" title="other_char">other_char</a> | ':' <a href="#var" title="var">var</a> ( ':' <a href="#type" title="type">type</a> )? | <a href="#quoted_string" title="quoted_string">quoted_string</a> | <a href="#quoted_identifier" title="quoted_identifier">quoted_identifier</a> | <a href="#comment" title="comment">comment</a> | '(' [^:] )*</div></code></div>
</p>
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">referenced by:
<ul>
Expand Down Expand Up @@ -788,7 +798,7 @@
<li><a href="#bracketed_text" title="bracketed_text">bracketed_text</a></li>
<li><a href="#sql_text" title="sql_text">sql_text</a></li>
</ul>
</p><br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><a name="other_char">other_char:</a></p><svg xmlns="http://www.w3.org/2000/svg" width="123" height="37">
</p><br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><a name="other_char">other_char:</a></p><svg xmlns="http://www.w3.org/2000/svg" width="129" height="37">
<defs>
<style type="text/css">
@namespace "http://www.w3.org/2000/svg";
Expand Down Expand Up @@ -820,15 +830,15 @@
</defs>
<polygon points="9 17 1 13 1 21"/>
<polygon points="17 17 9 13 9 21"/>
<polygon points="31 19 38 3 88 3 95 19 88 35 38 35"/>
<polygon points="29 17 36 1 86 1 93 17 86 33 36 33" class="regexp"/>
<text class="regexp" x="44" y="21">[^'"(]</text>
<path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 17 h2 m0 0 h10 m64 0 h10 m3 0 h-3"/>
<polygon points="113 17 121 13 121 21"/>
<polygon points="113 17 105 13 105 21"/></svg><p xmlns:xhtml="http://www.w3.org/1999/xhtml">
<polygon points="31 19 38 3 94 3 101 19 94 35 38 35"/>
<polygon points="29 17 36 1 92 1 99 17 92 33 36 33" class="regexp"/>
<text class="regexp" x="44" y="21">[^'"(:]</text>
<path xmlns:svg="http://www.w3.org/2000/svg" class="line" d="m17 17 h2 m0 0 h10 m70 0 h10 m3 0 h-3"/>
<polygon points="119 17 127 13 127 21"/>
<polygon points="119 17 111 13 111 21"/></svg><p xmlns:xhtml="http://www.w3.org/1999/xhtml">
<div class="ebnf"><code>
<div><a href="#other_char" title="other_char">other_char</a></div>
<div>         ::= [^'"(]</div></code></div>
<div>         ::= [^'"(:]</div></code></div>
</p>
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">referenced by:
<ul>
Expand Down Expand Up @@ -1171,6 +1181,7 @@
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">referenced by:
<ul>
<li><a href="#bracketed_text" title="bracketed_text">bracketed_text</a></li>
<li><a href="#sql_text" title="sql_text">sql_text</a></li>
</ul>
</p><br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><p xmlns:xhtml="http://www.w3.org/1999/xhtml" style="font-size: 14px; font-weight:bold"><a name="type">type:</a></p><svg xmlns="http://www.w3.org/2000/svg" width="283" height="335">
<defs>
Expand Down Expand Up @@ -1237,6 +1248,7 @@
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">referenced by:
<ul>
<li><a href="#bracketed_text" title="bracketed_text">bracketed_text</a></li>
<li><a href="#sql_text" title="sql_text">sql_text</a></li>
</ul>
</p><br xmlns:xhtml="http://www.w3.org/1999/xhtml" /><hr xmlns:xhtml="http://www.w3.org/1999/xhtml" />
<p xmlns:xhtml="http://www.w3.org/1999/xhtml">
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.markgrand.smileyVars</groupId>
<artifactId>smiley-vars</artifactId>
<version>0.2.1-RELEASE</version>
<version>0.2.2-RELEASE</version>
<packaging>jar</packaging>

<name>SmileyVars</name>
Expand Down
89 changes: 72 additions & 17 deletions src/main/java/com/markgrand/smileyVars/SmileyVarsTemplate.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package com.markgrand.smileyVars;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Stack;

/**
* A template for SQL that expands to leave out extraneous portions of a query.
*
* @author Mark Grand
*/
public class SmileyVarsTemplate {
private static final Logger logger = LoggerFactory.getLogger(SmileyVarsTemplate.class);

private final Tokenizer.TokenizerBuilder builder;
private final String sql;
private final ValueFormatterRegistry formatterRegistry;
Expand Down Expand Up @@ -80,38 +86,85 @@ public static SmileyVarsTemplate sqlServerTemplate(String sql) {
* @param values Apply the given values to this template
* @return the template
* @throws NoFormatterException if there is no applicable formatter registered to format a variable's value.
* @throws UnsupportedFeatureException if the template uses a smileyVars feature that is not yet supported.
*/
@SuppressWarnings("unused")
public String apply(Map<String, Object> values) {
public String apply(Map<String, Object> values) throws UnsupportedFeatureException {
Tokenizer tokenizer = builder.build(sql);
StringBuilder sb = new StringBuilder(sql.length() * 2);
StringBuilder segment = null;
StringBuilder segment = new StringBuilder(sql.length() * 2);
Stack<StringBuilder> stack = new Stack<>();
while (tokenizer.hasNext()) {
Token token = tokenizer.next();
switch (token.getTokenType()) {
case EOF:
return sb.toString();
return finalizeExpansion(segment, stack);
case TEXT:
((segment != null) ? segment : sb).append(token.getTokenchars());
processText(segment, token);
break;
case VAR:
segment = doVarExpansion(values, tokenizer, segment, token);
segment = processVar(values, tokenizer, segment, token, stack);
break;
case SMILEY_OPEN:
segment = new StringBuilder();
segment = processBracketOpen(segment, stack);
break;
case SMILEY_CLOSE:
if (segment!=null) {
sb.append(segment);
segment = null;
}
segment = processBracketClose(segment, stack);
break;
}
}
if (segment!=null) {
sb.append(segment);
return finalizeExpansion(segment, stack);
}

private void processText(StringBuilder segment, Token token) {
if (segment != null) {
segment.append(token.getTokenchars());
}
}

private StringBuilder processVar(Map<String, Object> values, Tokenizer tokenizer,
StringBuilder segment, Token token, Stack<StringBuilder> stack) {
if (segment != null) {
segment = doVarExpansion(values, tokenizer, segment, token);
if (segment == null && stack.isEmpty()) {
throw new UnboundVariableException("No value is provided for :" + token.getTokenchars());
}
}
return segment;
}

private StringBuilder processBracketOpen(StringBuilder segment, Stack<StringBuilder> stack) {
stack.push(segment);
segment = new StringBuilder();
return segment;
}

private StringBuilder processBracketClose(StringBuilder segment, Stack<StringBuilder> stack) {
if (stack.isEmpty()) {
logger.warn("SmileyVars template has an extra close bracket: {}", sql);
} else {
StringBuilder subSegment = segment;
segment = stack.pop();
if (subSegment != null) {
segment.append(subSegment);
}
}
return segment;
}

private String finalizeExpansion(StringBuilder segment, Stack<StringBuilder> stack) {
if (segment == null) {
segment = new StringBuilder();
}
while (!stack.isEmpty()) {
StringBuilder subSegment = segment;
segment = stack.pop();
if (segment != null) {
segment.append(subSegment);
} else {
segment = new StringBuilder();
}
}
return sb.toString();
return segment.toString();
}

/**
Expand All @@ -127,7 +180,7 @@ public String apply(Map<String, Object> values) {
private StringBuilder doVarExpansion(Map<String, Object> values, Tokenizer tokenizer, StringBuilder segment, Token varToken) {
String value = getVarValue(values, tokenizer, varToken);
if (value == null) {
skipPastSmileyClose(tokenizer);
skipToSmileyClose(tokenizer);
return null;
} else {
assert segment != null;
Expand Down Expand Up @@ -158,12 +211,14 @@ private String getVarValue(Map<String, Object> values, Tokenizer tokenizer, Toke
return formatterRegistry.format(values.get(varName));
}

private void skipPastSmileyClose(Tokenizer tokenizer) {
private void skipToSmileyClose(Tokenizer tokenizer) {
while (tokenizer.hasNext()) {
TokenType tokenType = tokenizer.next().getTokenType();
TokenType tokenType = tokenizer.peek();
if (TokenType.SMILEY_CLOSE.equals(tokenType) || TokenType.EOF.equals(tokenType)) {
return;
}
// Ignore next token.
tokenizer.next();
}
}
}
Loading

0 comments on commit d4cb876

Please sign in to comment.