Skip to content

Commit 80751ca

Browse files
committed
Initial attempt at making SqlColumn extendable
1 parent 2135727 commit 80751ca

File tree

3 files changed

+172
-51
lines changed

3 files changed

+172
-51
lines changed

src/main/java/org/mybatis/dynamic/sql/SqlColumn.java

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
2626
import org.mybatis.dynamic.sql.util.StringUtilities;
2727

28-
public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
28+
public class SqlColumn<T> implements BindableColumn<T>, SortSpecification, SqlColumnBuilders {
2929

3030
protected final String name;
3131
protected final SqlTable table;
@@ -39,7 +39,7 @@ public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
3939
protected final @Nullable Class<T> javaType;
4040
protected final @Nullable String javaProperty;
4141

42-
private SqlColumn(Builder<T> builder) {
42+
protected SqlColumn(AbstractBuilder<T, ?> builder) {
4343
name = Objects.requireNonNull(builder.name);
4444
table = Objects.requireNonNull(builder.table);
4545
jdbcType = builder.jdbcType;
@@ -91,15 +91,13 @@ public Optional<String> javaProperty() {
9191
}
9292

9393
@Override
94-
public SortSpecification descending() {
95-
Builder<T> b = copy();
96-
return b.withDescendingPhrase(" DESC").build(); //$NON-NLS-1$
94+
public SqlColumn<T> descending() {
95+
return copyBuilder().withDescendingPhrase(" DESC").build(); //$NON-NLS-1$
9796
}
9897

9998
@Override
10099
public SqlColumn<T> as(String alias) {
101-
Builder<T> b = copy();
102-
return b.withAlias(alias).build();
100+
return copyBuilder().withAlias(alias).build();
103101
}
104102

105103
/**
@@ -110,9 +108,7 @@ public SqlColumn<T> as(String alias) {
110108
* @return a new column that will be rendered with the specified table qualifier
111109
*/
112110
public SqlColumn<T> qualifiedWith(String tableQualifier) {
113-
Builder<T> b = copy();
114-
b.withTableQualifier(tableQualifier);
115-
return b.build();
111+
return copyBuilder().withTableQualifier(tableQualifier).build();
116112
}
117113

118114
/**
@@ -127,8 +123,8 @@ public SqlColumn<T> qualifiedWith(String tableQualifier) {
127123
* @return a new column aliased with a camel case version of the column name
128124
*/
129125
public SqlColumn<T> asCamelCase() {
130-
Builder<T> b = copy();
131-
return b.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build(); //$NON-NLS-1$ //$NON-NLS-2$
126+
return copyBuilder()
127+
.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build(); //$NON-NLS-1$ //$NON-NLS-2$
132128
}
133129

134130
@Override
@@ -150,29 +146,40 @@ public Optional<RenderingStrategy> renderingStrategy() {
150146
return Optional.ofNullable(renderingStrategy);
151147
}
152148

149+
@Override
153150
public <S> SqlColumn<S> withTypeHandler(String typeHandler) {
154-
Builder<S> b = copy();
155-
return b.withTypeHandler(typeHandler).build();
151+
return cast(copyBuilder().withTypeHandler(typeHandler).build());
156152
}
157153

154+
@Override
158155
public <S> SqlColumn<S> withRenderingStrategy(RenderingStrategy renderingStrategy) {
159-
Builder<S> b = copy();
160-
return b.withRenderingStrategy(renderingStrategy).build();
156+
return cast(copyBuilder().withRenderingStrategy(renderingStrategy).build());
161157
}
162158

159+
@Override
160+
@SuppressWarnings("unchecked")
163161
public <S> SqlColumn<S> withParameterTypeConverter(ParameterTypeConverter<S, ?> parameterTypeConverter) {
164-
Builder<S> b = copy();
165-
return b.withParameterTypeConverter(parameterTypeConverter).build();
162+
return cast(copyBuilder().withParameterTypeConverter((ParameterTypeConverter<T, ?>) parameterTypeConverter).build());
166163
}
167164

165+
@Override
166+
@SuppressWarnings("unchecked")
168167
public <S> SqlColumn<S> withJavaType(Class<S> javaType) {
169-
Builder<S> b = copy();
170-
return b.withJavaType(javaType).build();
168+
return cast(copyBuilder().withJavaType((Class<T>) javaType).build());
171169
}
172170

171+
@Override
173172
public <S> SqlColumn<S> withJavaProperty(String javaProperty) {
174-
Builder<S> b = copy();
175-
return b.withJavaProperty(javaProperty).build();
173+
return cast(copyBuilder().withJavaProperty(javaProperty).build());
174+
}
175+
176+
private Builder<T> copyBuilder() {
177+
return populateBaseBuilder(new Builder<>());
178+
}
179+
180+
@SuppressWarnings("unchecked")
181+
protected <S extends SqlColumn<?>> S cast(SqlColumn<?> column) {
182+
return (S) column;
176183
}
177184

178185
/**
@@ -181,22 +188,22 @@ public <S> SqlColumn<S> withJavaProperty(String javaProperty) {
181188
* chaining in the "with" methods. With this bit of fiction, we force the compiler to delay type
182189
* inference to the last method in the chain.
183190
*
184-
* @param <S> the type. Will be the same as T for this usage.
185-
* @return a new SqlColumn of type S (S is the same as T)
191+
* @param <B> the concrete builder type
192+
* @return the populated builder
186193
*/
187194
@SuppressWarnings("unchecked")
188-
private <S> Builder<S> copy() {
189-
return new Builder<S>()
195+
protected <B extends AbstractBuilder<T, ?>> B populateBaseBuilder(B builder) {
196+
return (B) builder
190197
.withName(this.name)
191198
.withTable(this.table)
192199
.withJdbcType(this.jdbcType)
193200
.withDescendingPhrase(this.descendingPhrase)
194201
.withAlias(this.alias)
195202
.withTypeHandler(this.typeHandler)
196203
.withRenderingStrategy(this.renderingStrategy)
197-
.withParameterTypeConverter((ParameterTypeConverter<S, ?>) this.parameterTypeConverter)
204+
.withParameterTypeConverter(this.parameterTypeConverter)
198205
.withTableQualifier(this.tableQualifier)
199-
.withJavaType((Class<S>) this.javaType)
206+
.withJavaType(this.javaType)
200207
.withJavaProperty(this.javaProperty);
201208
}
202209

@@ -213,7 +220,7 @@ public static <T> SqlColumn<T> of(String name, SqlTable table, JDBCType jdbcType
213220
.build();
214221
}
215222

216-
public static class Builder<T> {
223+
public static abstract class AbstractBuilder<T, B extends AbstractBuilder<T, B>> {
217224
protected @Nullable String name;
218225
protected @Nullable SqlTable table;
219226
protected @Nullable JDBCType jdbcType;
@@ -226,63 +233,72 @@ public static class Builder<T> {
226233
protected @Nullable Class<T> javaType;
227234
protected @Nullable String javaProperty;
228235

229-
public Builder<T> withName(String name) {
236+
public B withName(String name) {
230237
this.name = name;
231-
return this;
238+
return getThis();
232239
}
233240

234-
public Builder<T> withTable(SqlTable table) {
241+
public B withTable(SqlTable table) {
235242
this.table = table;
236-
return this;
243+
return getThis();
237244
}
238245

239-
public Builder<T> withJdbcType(@Nullable JDBCType jdbcType) {
246+
public B withJdbcType(@Nullable JDBCType jdbcType) {
240247
this.jdbcType = jdbcType;
241-
return this;
248+
return getThis();
242249
}
243250

244-
public Builder<T> withDescendingPhrase(String descendingPhrase) {
251+
public B withDescendingPhrase(String descendingPhrase) {
245252
this.descendingPhrase = descendingPhrase;
246-
return this;
253+
return getThis();
247254
}
248255

249-
public Builder<T> withAlias(@Nullable String alias) {
256+
public B withAlias(@Nullable String alias) {
250257
this.alias = alias;
251-
return this;
258+
return getThis();
252259
}
253260

254-
public Builder<T> withTypeHandler(@Nullable String typeHandler) {
261+
public B withTypeHandler(@Nullable String typeHandler) {
255262
this.typeHandler = typeHandler;
256-
return this;
263+
return getThis();
257264
}
258265

259-
public Builder<T> withRenderingStrategy(@Nullable RenderingStrategy renderingStrategy) {
266+
public B withRenderingStrategy(@Nullable RenderingStrategy renderingStrategy) {
260267
this.renderingStrategy = renderingStrategy;
261-
return this;
268+
return getThis();
262269
}
263270

264-
public Builder<T> withParameterTypeConverter(ParameterTypeConverter<T, ?> parameterTypeConverter) {
271+
public B withParameterTypeConverter(ParameterTypeConverter<T, ?> parameterTypeConverter) {
265272
this.parameterTypeConverter = parameterTypeConverter;
266-
return this;
273+
return getThis();
267274
}
268275

269-
private Builder<T> withTableQualifier(@Nullable String tableQualifier) {
276+
public B withTableQualifier(@Nullable String tableQualifier) {
270277
this.tableQualifier = tableQualifier;
271-
return this;
278+
return getThis();
272279
}
273280

274-
public Builder<T> withJavaType(@Nullable Class<T> javaType) {
281+
public B withJavaType(@Nullable Class<T> javaType) {
275282
this.javaType = javaType;
276-
return this;
283+
return getThis();
277284
}
278285

279-
public Builder<T> withJavaProperty(@Nullable String javaProperty) {
286+
public B withJavaProperty(@Nullable String javaProperty) {
280287
this.javaProperty = javaProperty;
281-
return this;
288+
return getThis();
282289
}
283290

291+
protected abstract B getThis();
292+
}
293+
294+
public static class Builder<T> extends AbstractBuilder<T, Builder<T>> {
284295
public SqlColumn<T> build() {
285296
return new SqlColumn<>(this);
286297
}
298+
299+
@Override
300+
protected Builder<T> getThis() {
301+
return this;
302+
}
287303
}
288304
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.mybatis.dynamic.sql;
2+
3+
import org.mybatis.dynamic.sql.render.RenderingStrategy;
4+
5+
public interface SqlColumnBuilders {
6+
<S> SqlColumnBuilders withTypeHandler(String typeHandler);
7+
8+
<S> SqlColumnBuilders withRenderingStrategy(RenderingStrategy renderingStrategy);
9+
10+
<S> SqlColumnBuilders withParameterTypeConverter(
11+
ParameterTypeConverter<S, ?> parameterTypeConverter);
12+
13+
<S> SqlColumnBuilders withJavaType(Class<S> javaType);
14+
15+
<S> SqlColumnBuilders withJavaProperty(String javaProperty);
16+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package examples.simple;
2+
3+
import org.mybatis.dynamic.sql.ParameterTypeConverter;
4+
import org.mybatis.dynamic.sql.SqlColumn;
5+
import org.mybatis.dynamic.sql.render.RenderingStrategy;
6+
import org.mybatis.dynamic.sql.util.StringUtilities;
7+
8+
public class PrimaryKeyColumn<T> extends SqlColumn<T> {
9+
private final boolean isPrimaryKeyColumn;
10+
11+
private PrimaryKeyColumn(Builder<T> builder) {
12+
super(builder);
13+
isPrimaryKeyColumn = builder.isPrimaryKeyColumn;
14+
}
15+
16+
public boolean isPrimaryKeyColumn() {
17+
return isPrimaryKeyColumn;
18+
}
19+
20+
@Override
21+
public PrimaryKeyColumn<T> descending() {
22+
return copyBuilder().withDescendingPhrase(" DESC").build(); //$NON-NLS-1$
23+
}
24+
25+
@Override
26+
public PrimaryKeyColumn<T> as(String alias) {
27+
return copyBuilder().withAlias(alias).build();
28+
}
29+
30+
@Override
31+
public PrimaryKeyColumn<T> qualifiedWith(String tableQualifier) {
32+
return copyBuilder().withTableQualifier(tableQualifier).build();
33+
}
34+
35+
@Override
36+
public PrimaryKeyColumn<T> asCamelCase() {
37+
return copyBuilder()
38+
.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build(); //$NON-NLS-1$ //$NON-NLS-2$
39+
}
40+
41+
@Override
42+
public <S> PrimaryKeyColumn<S> withTypeHandler(String typeHandler) {
43+
return cast(copyBuilder().withTypeHandler(typeHandler).build());
44+
}
45+
46+
@Override
47+
public <S> PrimaryKeyColumn<S> withRenderingStrategy(RenderingStrategy renderingStrategy) {
48+
return cast(copyBuilder().withRenderingStrategy(renderingStrategy).build());
49+
}
50+
51+
@Override
52+
@SuppressWarnings("unchecked")
53+
public <S> PrimaryKeyColumn<S> withParameterTypeConverter(ParameterTypeConverter<S, ?> parameterTypeConverter) {
54+
return cast(copyBuilder().withParameterTypeConverter((ParameterTypeConverter<T, ?>) parameterTypeConverter).build());
55+
}
56+
57+
@Override
58+
@SuppressWarnings("unchecked")
59+
public <S> PrimaryKeyColumn<S> withJavaType(Class<S> javaType) {
60+
return cast(copyBuilder().withJavaType((Class<T>) javaType).build());
61+
}
62+
63+
@Override
64+
public <S> PrimaryKeyColumn<S> withJavaProperty(String javaProperty) {
65+
return cast(copyBuilder().withJavaProperty(javaProperty).build());
66+
}
67+
68+
private Builder<T> copyBuilder() {
69+
return populateBaseBuilder(new Builder<>());
70+
}
71+
72+
public static class Builder<T> extends AbstractBuilder<T, Builder<T>> {
73+
private boolean isPrimaryKeyColumn;
74+
75+
public Builder<T> isPrimaryKeyColumn(boolean isPrimaryKeyColumn) {
76+
this.isPrimaryKeyColumn = isPrimaryKeyColumn;
77+
return this;
78+
}
79+
80+
public PrimaryKeyColumn<T> build() {
81+
return new PrimaryKeyColumn<>(this);
82+
}
83+
84+
@Override
85+
protected Builder<T> getThis() {
86+
return this;
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)