Skip to content
This repository was archived by the owner on Mar 12, 2020. It is now read-only.

Commit 7e03102

Browse files
author
Eric Meyer
committed
Adds support for unscopedJsonColumns to be able to merge in JSON column data to the top level properties. Deprecates property "jsonColumnNames" in favor of more explicit "scopedJsonColumns" for the same behavior. Adds new property "unscopedJsonColumns" for columns that should be merged into the top-level item properties.
1 parent 4bddf4a commit 7e03102

15 files changed

+456
-42
lines changed

src/docroot/WEB-INF/classes/datatool-config-7.xsd

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,15 @@
147147
<element name="subquery" type="tns:SubQueryType" minOccurs="0" maxOccurs="unbounded"/>
148148
</sequence>
149149
<attribute name="idColumn" type="string" use="required"/>
150-
<attribute name="jsonColumnNames" type="string" use="optional"/>
150+
<attribute name="jsonColumnNames" type="string" use="optional">
151+
<annotation>
152+
<documentation>
153+
Deprecated. Used scopedJsonColumns for the same functionality.
154+
</documentation>
155+
</annotation>
156+
</attribute>
157+
<attribute name="scopedJsonColumns" type="string" use="optional"/>
158+
<attribute name="unscopedJsonColumns" type="string" use="optional"/>
151159
<attribute name="providerColumn" use="optional" type="string"/>
152160
<attribute name="kindColumn" use="optional" type="string"/>
153161
</complexType>

src/main/java/com/t11e/discovery/datatool/ConfigurationManager.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,17 @@ private void fillActionBeanDefinition(final BeanDefinitionBuilder builder, final
377377
builder.addPropertyValue("idColumn", parentElementToQuery.valueOf("@idColumn"));
378378
addAttributeValueIfNotNull(builder, parentElementToQuery, "providerColumn");
379379
addAttributeValueIfNotNull(builder, parentElementToQuery, "kindColumn");
380-
builder.addPropertyValue("jsonColumnNames", parentElementToQuery.valueOf("@jsonColumnNames"));
380+
{
381+
final String legacyScopedJsonColums = parentElementToQuery.valueOf("@jsonColumnNames");
382+
final String scopedJsonColumns = parentElementToQuery.valueOf("@scopedJsonColumns");
383+
if (StringUtils.isNotBlank(legacyScopedJsonColums) && StringUtils.isNotBlank(scopedJsonColumns))
384+
{
385+
throw new RuntimeException("You cannot specify both jsonColumnNames and scopedJsonColumnNames. Please just use scopedJsonColumnNames.");
386+
}
387+
final String columns = StringUtils.isNotBlank(scopedJsonColumns) ? scopedJsonColumns : legacyScopedJsonColums;
388+
builder.addPropertyValue("scopedJsonColumns", columns);
389+
}
390+
builder.addPropertyValue("unscopedJsonColumns", parentElementToQuery.valueOf("@unscopedJsonColumns"));
381391
builder
382392
.addPropertyValue("query",
383393
StringUtils.trimToEmpty(parentElementToQuery.valueOf("c:query/text()".replace("c:", ns))));

src/main/java/com/t11e/discovery/datatool/CreateActionRowCallbackHandler.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public CreateActionRowCallbackHandler(
5555
final String providerColumn,
5656
final String kindColumn,
5757
final PropertyCase propertyCase,
58-
final Set<String> jsonColumns,
58+
final Set<String> scopedJsonColumns,
59+
final Set<String> unscopedJsonColumns,
5960
final List<MergeColumns> mergeColumns,
6061
final List<SubQuery> subqueries,
6162
final boolean shouldRecordTimings)
@@ -84,7 +85,7 @@ public CreateActionRowCallbackHandler(
8485
{
8586
changeValueCaseColumns = Collections.emptySet();
8687
}
87-
resultSetConvertor = new ResultSetConvertor(propertyCase, jsonColumns, changeValueCaseColumns);
88+
resultSetConvertor = new ResultSetConvertor(propertyCase, scopedJsonColumns, unscopedJsonColumns, changeValueCaseColumns);
8889
}
8990
if (this.subqueries.isEmpty())
9091
{
@@ -99,7 +100,8 @@ public CreateActionRowCallbackHandler(
99100
? Collections.<String> emptySet()
100101
: Collections.singleton(subquery.getDiscriminator());
101102
subqueryConvertors.add(
102-
new ResultSetConvertor(propertyCase, Collections.<String> emptySet(), changeValueCaseColumns));
103+
new ResultSetConvertor(propertyCase, Collections.<String> emptySet(), Collections.<String> emptySet(),
104+
changeValueCaseColumns));
103105
}
104106
}
105107
}

src/main/java/com/t11e/discovery/datatool/ResultSetConvertor.java

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@
33
import java.sql.ResultSet;
44
import java.sql.ResultSetMetaData;
55
import java.sql.SQLException;
6+
import java.util.ArrayList;
67
import java.util.Collections;
78
import java.util.HashSet;
89
import java.util.LinkedHashMap;
10+
import java.util.List;
911
import java.util.Map;
1012
import java.util.Set;
1113

14+
import org.apache.commons.lang.StringUtils;
15+
1216
import com.t11e.discovery.datatool.column.BooleanColumnProcessor;
1317
import com.t11e.discovery.datatool.column.DateColumnProcessor;
14-
import com.t11e.discovery.datatool.column.IColumnProcessor;
18+
import com.t11e.discovery.datatool.column.IItemPropertiesFromColumnProcessor;
19+
import com.t11e.discovery.datatool.column.ItemPropertiesFromColumnProcessor;
20+
import com.t11e.discovery.datatool.column.ItemPropertiesFromUnscopedJsonColumnProcessor;
1521
import com.t11e.discovery.datatool.column.JsonColumnProcessor;
1622
import com.t11e.discovery.datatool.column.LowerCaseStringColumnProcessor;
1723
import com.t11e.discovery.datatool.column.StringColumnProcessor;
@@ -21,13 +27,30 @@
2127

2228
public class ResultSetConvertor
2329
{
30+
private static final IItemPropertiesFromColumnProcessor JSON = new ItemPropertiesFromColumnProcessor(
31+
JsonColumnProcessor.INSTANCE);
32+
private static final IItemPropertiesFromColumnProcessor[] LOWER_STRING = new IItemPropertiesFromColumnProcessor[]{
33+
new ItemPropertiesFromColumnProcessor(LowerCaseStringColumnProcessor.INSTANCE)};
34+
private static final IItemPropertiesFromColumnProcessor[] UPPER_STRING = new IItemPropertiesFromColumnProcessor[]{
35+
new ItemPropertiesFromColumnProcessor(UpperCaseStringColumnProcessor.INSTANCE)};
36+
private static final IItemPropertiesFromColumnProcessor[] STRING = new IItemPropertiesFromColumnProcessor[]{
37+
new ItemPropertiesFromColumnProcessor(StringColumnProcessor.INSTANCE)};
38+
private static final IItemPropertiesFromColumnProcessor[] DATE = new IItemPropertiesFromColumnProcessor[]{
39+
new ItemPropertiesFromColumnProcessor(DateColumnProcessor.INSTANCE)};
40+
private static final IItemPropertiesFromColumnProcessor[] TIME = new IItemPropertiesFromColumnProcessor[]{
41+
new ItemPropertiesFromColumnProcessor(TimeColumnProcessor.INSTANCE)};
42+
private static final IItemPropertiesFromColumnProcessor[] TIMESTAMP = new IItemPropertiesFromColumnProcessor[]{
43+
new ItemPropertiesFromColumnProcessor(TimestampColumnProcessor.INSTANCE)};
44+
2445
private final PropertyCase propertyCase;
25-
private final Set<String> jsonColumns;
46+
private final Set<String> scopedJsonColumns;
47+
private final Set<String> unscopedJsonColumns;
2648
private final Set<String> changeValueCaseColumns;
27-
private IColumnProcessor[] columnProcessors;
49+
private IItemPropertiesFromColumnProcessor[][] columnProcessors;
2850
private String[] columnNames;
2951

30-
public ResultSetConvertor(final PropertyCase propertyCase, final Set<String> jsonColumns,
52+
public ResultSetConvertor(final PropertyCase propertyCase, final Set<String> scopedJsonColumns,
53+
final Set<String> unscopedJsonColumns,
3154
final Set<String> potentialChangeValueCaseColumns)
3255
{
3356
this.propertyCase = propertyCase;
@@ -43,7 +66,8 @@ public ResultSetConvertor(final PropertyCase propertyCase, final Set<String> jso
4366
{
4467
changeValueCaseColumns = Collections.emptySet();
4568
}
46-
this.jsonColumns = jsonColumns != null ? jsonColumns : Collections.<String> emptySet();
69+
this.scopedJsonColumns = scopedJsonColumns != null ? scopedJsonColumns : Collections.<String> emptySet();
70+
this.unscopedJsonColumns = unscopedJsonColumns != null ? unscopedJsonColumns : Collections.<String> emptySet();
4771
}
4872

4973
public Map<String, Object> getRowAsMap(final ResultSet rs)
@@ -55,14 +79,13 @@ public Map<String, Object> getRowAsMap(final ResultSet rs)
5579
for (int idx = 0; idx < columnProcessors.length; ++idx)
5680
{
5781
final int column = idx + 1;
58-
final IColumnProcessor columnProcessor = columnProcessors[idx];
59-
if (columnProcessor != null)
82+
final IItemPropertiesFromColumnProcessor[] processors = columnProcessors[idx];
83+
if (processors != null)
6084
{
6185
final String name = columnNames[idx];
62-
final Object value = columnProcessor.processColumn(rs, column);
63-
if (value != null)
86+
for (final IItemPropertiesFromColumnProcessor processor : processors)
6487
{
65-
properties.put(name, value);
88+
processor.processColumn(properties, rs, column, name);
6689
}
6790
}
6891
}
@@ -75,7 +98,7 @@ private void lazyInitialize(final ResultSet rs)
7598
if (columnProcessors == null)
7699
{
77100
final ResultSetMetaData metaData = rs.getMetaData();
78-
final IColumnProcessor[] processors = new IColumnProcessor[metaData.getColumnCount()];
101+
final IItemPropertiesFromColumnProcessor[][] processors = new IItemPropertiesFromColumnProcessor[metaData.getColumnCount()][];
79102
final String[] names = new String[processors.length];
80103
for (int idx = 0; idx < processors.length; idx++)
81104
{
@@ -89,18 +112,18 @@ private void lazyInitialize(final ResultSet rs)
89112
}
90113
}
91114

92-
private IColumnProcessor getColumnProcessor(
115+
private IItemPropertiesFromColumnProcessor[] getColumnProcessor(
93116
final ResultSetMetaData md,
94117
final int column,
95118
final String columnLabel)
96119
throws SQLException
97120
{
98-
IColumnProcessor output;
121+
IItemPropertiesFromColumnProcessor[] output;
99122
switch (md.getColumnType(column))
100123
{
101124
case java.sql.Types.BIT:
102125
case java.sql.Types.BOOLEAN:
103-
output = BooleanColumnProcessor.INSTANCE;
126+
output = new ItemPropertiesFromColumnProcessor[]{new ItemPropertiesFromColumnProcessor(BooleanColumnProcessor.INSTANCE)};
104127
break;
105128
case java.sql.Types.TINYINT:
106129
case java.sql.Types.SMALLINT:
@@ -111,46 +134,58 @@ private IColumnProcessor getColumnProcessor(
111134
case java.sql.Types.DOUBLE:
112135
case java.sql.Types.NUMERIC:
113136
case java.sql.Types.DECIMAL:
114-
output = StringColumnProcessor.INSTANCE;
137+
output = STRING;
115138
break;
116139
case java.sql.Types.CHAR:
117140
case java.sql.Types.VARCHAR:
118141
case java.sql.Types.LONGVARCHAR:
119142
case java.sql.Types.CLOB:
120143
{
121-
if (columnLabel != null && jsonColumns.contains(columnLabel))
144+
final String columnLabelLower = StringUtils.lowerCase(columnLabel);
145+
if (columnLabel != null &&
146+
(scopedJsonColumns.contains(columnLabelLower)
147+
|| unscopedJsonColumns.contains(columnLabelLower)))
122148
{
123-
output = JsonColumnProcessor.INSTANCE;
149+
final List<IItemPropertiesFromColumnProcessor> jsonProcessors = new ArrayList<IItemPropertiesFromColumnProcessor>(2);
150+
if (scopedJsonColumns.contains(columnLabelLower))
151+
{
152+
jsonProcessors.add(JSON);
153+
}
154+
if (unscopedJsonColumns.contains(columnLabelLower))
155+
{
156+
jsonProcessors.add(new ItemPropertiesFromUnscopedJsonColumnProcessor(JsonColumnProcessor.INSTANCE, propertyCase));
157+
}
158+
output = jsonProcessors.toArray(new IItemPropertiesFromColumnProcessor[jsonProcessors.size()]);
124159
}
125160
else if (columnLabel != null && changeValueCaseColumns.contains(columnLabel))
126161
{
127162
switch (propertyCase)
128163
{
129164
case LOWER:
130-
output = LowerCaseStringColumnProcessor.INSTANCE;
165+
output = LOWER_STRING;
131166
break;
132167
case UPPER:
133-
output = UpperCaseStringColumnProcessor.INSTANCE;
168+
output = UPPER_STRING;
134169
break;
135170
default:
136-
output = StringColumnProcessor.INSTANCE;
171+
output = STRING;
137172
break;
138173
}
139174
}
140175
else
141176
{
142-
output = StringColumnProcessor.INSTANCE;
177+
output = STRING;
143178
}
144179
break;
145180
}
146181
case java.sql.Types.DATE:
147-
output = DateColumnProcessor.INSTANCE;
182+
output = DATE;
148183
break;
149184
case java.sql.Types.TIME:
150-
output = TimeColumnProcessor.INSTANCE;
185+
output = TIME;
151186
break;
152187
case java.sql.Types.TIMESTAMP:
153-
output = TimestampColumnProcessor.INSTANCE;
188+
output = TIMESTAMP;
154189
break;
155190
case java.sql.Types.BINARY:
156191
case java.sql.Types.VARBINARY:

src/main/java/com/t11e/discovery/datatool/SqlAction.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Arrays;
44
import java.util.Collections;
55
import java.util.HashSet;
6+
import java.util.LinkedHashSet;
67
import java.util.List;
78
import java.util.ListIterator;
89
import java.util.Set;
@@ -26,7 +27,8 @@ public class SqlAction
2627
private String idColumn;
2728
private String providerColumn;
2829
private String kindColumn;
29-
private Set<String> jsonColumnNames = Collections.emptySet();
30+
private Set<String> scopedJsonColumns = Collections.emptySet();
31+
private Set<String> unscopedJsonColumns = Collections.emptySet();
3032
private PropertyCase propertyCase;
3133

3234
@Override
@@ -41,14 +43,16 @@ public void afterPropertiesSet()
4143
it.set(new MergeColumns(propertyCase.convert(merge.getKeyColumn()), propertyCase.convert(merge.getValueColumn())));
4244
}
4345
}
44-
CollectionUtils.transform(jsonColumnNames, new Transformer()
46+
final Transformer transformer = new Transformer()
4547
{
4648
@Override
4749
public String transform(final Object in)
4850
{
49-
return propertyCase.convert((String) in);
51+
return StringUtils.lowerCase((String) in);
5052
}
51-
});
53+
};
54+
CollectionUtils.transform(scopedJsonColumns, transformer);
55+
CollectionUtils.transform(unscopedJsonColumns, transformer);
5256
}
5357

5458
public Set<String> getFilter()
@@ -107,20 +111,24 @@ public String getIdColumn()
107111
return idColumn;
108112
}
109113

110-
public Set<String> getJsonColumnNames()
114+
public Set<String> getScopedJsonColumnsSet()
111115
{
112-
return jsonColumnNames;
116+
return scopedJsonColumns;
113117
}
114118

115-
public void setJsonColumnNames(final String jsonColumnNames)
119+
public void setScopedJsonColumns(final String scopedJsonColumns)
116120
{
117-
this.jsonColumnNames = new HashSet<String>(
118-
Arrays.asList(StringUtils.split(jsonColumnNames, ", ")));
121+
this.scopedJsonColumns = new LinkedHashSet<String>(Arrays.asList(StringUtils.split(scopedJsonColumns, ", ")));
119122
}
120123

121-
public void setJsonColumnNames(final Set<String> jsonColumnNames)
124+
public Set<String> getUnscopedJsonColumnsSet()
122125
{
123-
this.jsonColumnNames = jsonColumnNames;
126+
return unscopedJsonColumns;
127+
}
128+
129+
public void setUnscopedJsonColumns(final String unscopedJsonColumns)
130+
{
131+
this.unscopedJsonColumns = new LinkedHashSet<String>(Arrays.asList(StringUtils.split(unscopedJsonColumns, ", ")));
124132
}
125133

126134
public PropertyCase getPropertyCase()

src/main/java/com/t11e/discovery/datatool/SqlChangesetExtractor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ private void process(
119119
sqlAction.getProviderColumn(),
120120
sqlAction.getKindColumn(),
121121
sqlAction.getPropertyCase(),
122-
sqlAction.getJsonColumnNames(),
122+
sqlAction.getScopedJsonColumnsSet(),
123+
sqlAction.getUnscopedJsonColumnsSet(),
123124
sqlAction.getMergeColumns(),
124125
sqlAction.getSubqueries(),
125126
logTiming);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.t11e.discovery.datatool.column;
2+
3+
import java.sql.ResultSet;
4+
import java.sql.SQLException;
5+
import java.util.Map;
6+
7+
public interface IItemPropertiesFromColumnProcessor
8+
{
9+
/**
10+
* Sets properties on target item from current row in resultset for given column and property name
11+
*/
12+
public void processColumn(final Map<String, Object> target, ResultSet rs, int column, String propertyName)
13+
throws SQLException;
14+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.t11e.discovery.datatool.column;
2+
3+
import java.sql.ResultSet;
4+
import java.sql.SQLException;
5+
import java.util.Map;
6+
7+
public class ItemPropertiesFromColumnProcessor
8+
implements IItemPropertiesFromColumnProcessor
9+
{
10+
private final IColumnProcessor delegate;
11+
12+
public ItemPropertiesFromColumnProcessor(final IColumnProcessor delegate)
13+
{
14+
this.delegate = delegate;
15+
}
16+
17+
@Override
18+
public void processColumn(final Map<String, Object> target, final ResultSet rs, final int column,
19+
final String propertyName)
20+
throws SQLException
21+
{
22+
final Object value = delegate.processColumn(rs, column);
23+
if (value != null)
24+
{
25+
target.put(propertyName, value);
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)