1616public class Query {
1717 public static final TypedParameter NULL = TypedParameter .NULL ;
1818 public static final String NULL_STRING = "NULL" ;
19+ public static final String TRUE_STRING = "TRUE" ;
20+
21+ protected static final Pattern IN_CLAUSE_PATTERN = Pattern .compile ("((\\ ([^()]+\\ ))|(\\ w+))? IN[ ]*\\ (\\ ?\\ )" );
22+ protected static final Pattern TUPLE_PATTERN = Pattern .compile ("([^,()\\ s]+)" );
23+
24+ protected static class ExtendedInClauseParameters {
25+ public final List <InClauseParameter > inClauseParameters ;
26+ public final Boolean isExtendedInClause ;
27+
28+ public ExtendedInClauseParameters (final List <InClauseParameter > inClauseParameters , final Boolean isExtendedInClause ) {
29+ this .inClauseParameters = inClauseParameters ;
30+ this .isExtendedInClause = isExtendedInClause ;
31+ }
32+ }
1933
2034 protected static StringBuilder buildParenthesisList (final Integer parameterCount ) {
2135 final StringBuilder stringBuilder = new StringBuilder ();
@@ -64,25 +78,69 @@ protected static String buildInClause(final List<InClauseParameter> inClausePara
6478 return stringBuilder .toString ();
6579 }
6680
81+ protected static String buildAndList (final List <String > columnNames ) {
82+ final StringBuilder stringBuilder = new StringBuilder ();
83+
84+ String separator = "" ;
85+ for (final String columnName : columnNames ) {
86+ stringBuilder .append (separator );
87+ stringBuilder .append (columnName );
88+ stringBuilder .append (" = ?" );
89+ separator = " AND " ;
90+ }
91+
92+ return stringBuilder .toString ();
93+ }
94+
95+ protected static String buildExpandedWhereInClause (final List <String > columnNames , final Integer tupleCount ) {
96+ if (tupleCount == 0 ) { return TRUE_STRING ; }
97+
98+ final StringBuilder stringBuilder = new StringBuilder ();
99+ String separator = "" ;
100+ for (int i = 0 ; i < tupleCount ; ++i ) {
101+ stringBuilder .append (separator );
102+ stringBuilder .append ("(" );
103+
104+ stringBuilder .append (Query .buildAndList (columnNames ));
105+
106+ stringBuilder .append (")" );
107+
108+ separator = " OR " ;
109+ }
110+ return stringBuilder .toString ();
111+ }
112+
67113 protected final String _query ;
68114 protected final MutableList <TypedParameter > _parameters ;
69115 protected final ParameterFactory _parameterFactory ;
70116
71- protected final MutableList <List < InClauseParameter >> _inClauseParameters = new MutableList <List < InClauseParameter > >();
117+ protected final MutableList <ExtendedInClauseParameters > _inClauseParameters = new MutableList <ExtendedInClauseParameters >();
72118 protected final MutableList <Integer > _inClauseParameterIndexes = new MutableList <Integer >();
73119 protected Integer _nextParameterIndex = 0 ;
74120
75- protected void _setInClauseParameters (final InClauseParameter inClauseParameter , final InClauseParameter [] extraInClauseParameters ) {
121+ protected void _setInClauseParameters (final InClauseParameter inClauseParameter , final InClauseParameter [] extraInClauseParameters , final Boolean enableExpandedInClause ) {
76122 final MutableList <InClauseParameter > valueTuples = new MutableList <InClauseParameter >((extraInClauseParameters != null ? extraInClauseParameters .length : 0 ) + 1 );
77- valueTuples .add (inClauseParameter );
123+ valueTuples .add (Util . coalesce ( inClauseParameter , InClauseParameter . NULL ) );
78124
79125 if (extraInClauseParameters != null ) {
80126 for (final InClauseParameter extraInClauseParameter : extraInClauseParameters ) {
81127 valueTuples .add (extraInClauseParameter );
82128 }
83129 }
84130
85- _inClauseParameters .add (valueTuples );
131+ _inClauseParameters .add (new ExtendedInClauseParameters (valueTuples , enableExpandedInClause ));
132+ _inClauseParameterIndexes .add (_nextParameterIndex );
133+ _nextParameterIndex += 1 ;
134+ }
135+
136+ protected <T > void _setInClauseParameters (final Iterable <? extends T > values , final ValueExtractor <T > valueExtractor , final Boolean enableExpandedInClause ) {
137+ final MutableList <InClauseParameter > typedParameters = new MutableList <InClauseParameter >();
138+ for (final T value : values ) {
139+ final InClauseParameter inClauseParameter = valueExtractor .extractValues (value );
140+ typedParameters .add (Util .coalesce (inClauseParameter , InClauseParameter .NULL ));
141+ }
142+
143+ _inClauseParameters .add (new ExtendedInClauseParameters (typedParameters , enableExpandedInClause ));
86144 _inClauseParameterIndexes .add (_nextParameterIndex );
87145 _nextParameterIndex += 1 ;
88146 }
@@ -211,28 +269,32 @@ public Query setNullParameter() {
211269 }
212270
213271 public Query setInClauseParameters (final InClauseParameter inClauseParameter , final InClauseParameter ... extraInClauseParameters ) {
214- _setInClauseParameters (Util . coalesce ( inClauseParameter , InClauseParameter . NULL ), extraInClauseParameters );
272+ _setInClauseParameters (inClauseParameter , extraInClauseParameters , false );
215273 return this ;
216274 }
217275
218276 public <T > Query setInClauseParameters (final Iterable <? extends T > values , final ValueExtractor <T > valueExtractor ) {
219- final MutableList <InClauseParameter > typedParameters = new MutableList <InClauseParameter >();
220- for (final T value : values ) {
221- final InClauseParameter inClauseParameter = valueExtractor .extractValues (value );
222- typedParameters .add (Util .coalesce (inClauseParameter , InClauseParameter .NULL ));
223- }
277+ _setInClauseParameters (values , valueExtractor , false );
278+ return this ;
279+ }
224280
225- _inClauseParameters .add (typedParameters );
226- _inClauseParameterIndexes .add (_nextParameterIndex );
227- _nextParameterIndex += 1 ;
281+ public <T > Query setExpandedInClauseParameters (final InClauseParameter inClauseParameter , final InClauseParameter ... extraInClauseParameters ) {
282+ _setInClauseParameters (inClauseParameter , extraInClauseParameters , true );
283+ return this ;
284+ }
285+
286+ public <T > Query setExpandedInClauseParameters (final Iterable <? extends T > values , final ValueExtractor <T > valueExtractor ) {
287+ _setInClauseParameters (values , valueExtractor , true );
228288 return this ;
229289 }
230290
231291 public String getQueryString () {
232292 final int inClauseCount = _inClauseParameters .getCount ();
293+ if (inClauseCount == 0 ) {
294+ return _query ;
295+ }
233296
234- final Pattern pattern = Pattern .compile ("IN[ ]*\\ (\\ ?\\ )" );
235- final Matcher matcher = pattern .matcher (_query );
297+ final Matcher matcher = Query .IN_CLAUSE_PATTERN .matcher (_query );
236298
237299 final StringBuffer stringBuffer = new StringBuffer ();
238300 {
@@ -242,9 +304,28 @@ public String getQueryString() {
242304 break ;
243305 }
244306
245- final List <InClauseParameter > inClauseValues = _inClauseParameters .get (matchCount );
246- final String inClause = Query .buildInClause (inClauseValues );
247- matcher .appendReplacement (stringBuffer , inClause );
307+ final ExtendedInClauseParameters extendedInClauseParameters = _inClauseParameters .get (matchCount );
308+ final List <InClauseParameter > inClauseParameters = extendedInClauseParameters .inClauseParameters ;
309+ final Boolean useExpandedInClause = extendedInClauseParameters .isExtendedInClause ;
310+
311+ final String rawColumnNames = matcher .group (1 );
312+ if (useExpandedInClause ) {
313+ final Matcher columnNameMatcher = Query .TUPLE_PATTERN .matcher (rawColumnNames );
314+
315+ final MutableList <String > columnNames = new MutableList <String >();
316+ while (columnNameMatcher .find ()) {
317+ final String columnName = columnNameMatcher .group (1 );
318+ columnNames .add (columnName );
319+ }
320+
321+ final String inClause = Query .buildExpandedWhereInClause (columnNames , inClauseParameters .getCount ());
322+ matcher .appendReplacement (stringBuffer , inClause );
323+ }
324+ else {
325+ final String inClause = Query .buildInClause (inClauseParameters );
326+ matcher .appendReplacement (stringBuffer , (rawColumnNames + " " + inClause ));
327+ }
328+
248329 matchCount += 1 ;
249330 }
250331 matcher .appendTail (stringBuffer );
@@ -278,7 +359,8 @@ public java.util.List<TypedParameter> getParameters() {
278359 final int loopCount = (_parameters .getCount () + inClauseCount );
279360 for (int i = 0 ; i < loopCount ; ++i ) {
280361 if (nextInClauseParameterIndex == returnedParameterIndex ) {
281- for (final InClauseParameter inClauseParameter : _inClauseParameters .get (inClauseIndex )) {
362+ final ExtendedInClauseParameters extendedInClauseParameters = _inClauseParameters .get (inClauseIndex );
363+ for (final InClauseParameter inClauseParameter : extendedInClauseParameters .inClauseParameters ) {
282364 if (inClauseParameter .getType () == InClauseParameter .Type .NULL ) {
283365 parameters .add (TypedParameter .NULL );
284366 }
0 commit comments