1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.dynamic.sql;
17
18 import java.sql.JDBCType;
19 import java.util.Objects;
20 import java.util.Optional;
21
22 import org.jspecify.annotations.Nullable;
23 import org.mybatis.dynamic.sql.render.RenderingContext;
24 import org.mybatis.dynamic.sql.render.RenderingStrategy;
25 import org.mybatis.dynamic.sql.util.FragmentAndParameters;
26 import org.mybatis.dynamic.sql.util.StringUtilities;
27
28 public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
29
30 protected final String name;
31 protected final SqlTable table;
32 protected final @Nullable JDBCType jdbcType;
33 protected final String descendingPhrase;
34 protected final @Nullable String alias;
35 protected final @Nullable String typeHandler;
36 protected final @Nullable RenderingStrategy renderingStrategy;
37 protected final ParameterTypeConverter<T, ?> parameterTypeConverter;
38 protected final @Nullable String tableQualifier;
39 protected final @Nullable Class<T> javaType;
40
41 private SqlColumn(Builder<T> builder) {
42 name = Objects.requireNonNull(builder.name);
43 table = Objects.requireNonNull(builder.table);
44 jdbcType = builder.jdbcType;
45 descendingPhrase = builder.descendingPhrase;
46 alias = builder.alias;
47 typeHandler = builder.typeHandler;
48 renderingStrategy = builder.renderingStrategy;
49 parameterTypeConverter = Objects.requireNonNull(builder.parameterTypeConverter);
50 tableQualifier = builder.tableQualifier;
51 javaType = builder.javaType;
52 }
53
54 public String name() {
55 return name;
56 }
57
58 public SqlTable table() {
59 return table;
60 }
61
62 @Override
63 public Optional<JDBCType> jdbcType() {
64 return Optional.ofNullable(jdbcType);
65 }
66
67 @Override
68 public Optional<String> alias() {
69 return Optional.ofNullable(alias);
70 }
71
72 @Override
73 public Optional<String> typeHandler() {
74 return Optional.ofNullable(typeHandler);
75 }
76
77 @Override
78 public Optional<Class<T>> javaType() {
79 return Optional.ofNullable(javaType);
80 }
81
82 @Override
83 public @Nullable Object convertParameterType(@Nullable T value) {
84 return value == null ? null : parameterTypeConverter.convert(value);
85 }
86
87 @Override
88 public SortSpecification descending() {
89 Builder<T> b = copy();
90 return b.withDescendingPhrase(" DESC").build();
91 }
92
93 @Override
94 public SqlColumn<T> as(String alias) {
95 Builder<T> b = copy();
96 return b.withAlias(alias).build();
97 }
98
99
100
101
102
103
104
105
106 public SqlColumn<T> qualifiedWith(String tableQualifier) {
107 Builder<T> b = copy();
108 b.withTableQualifier(tableQualifier);
109 return b.build();
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123 public SqlColumn<T> asCamelCase() {
124 Builder<T> b = copy();
125 return b.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build();
126 }
127
128 @Override
129 public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) {
130 return FragmentAndParameters.fromFragment(alias().orElse(name) + descendingPhrase);
131 }
132
133 @Override
134 public FragmentAndParameters render(RenderingContext renderingContext) {
135 if (tableQualifier == null) {
136 return FragmentAndParameters.fromFragment(renderingContext.aliasedColumnName(this));
137 } else {
138 return FragmentAndParameters.fromFragment(renderingContext.aliasedColumnName(this, tableQualifier));
139 }
140 }
141
142 @Override
143 public Optional<RenderingStrategy> renderingStrategy() {
144 return Optional.ofNullable(renderingStrategy);
145 }
146
147 public <S> SqlColumn<S> withTypeHandler(String typeHandler) {
148 Builder<S> b = copy();
149 return b.withTypeHandler(typeHandler).build();
150 }
151
152 public <S> SqlColumn<S> withRenderingStrategy(RenderingStrategy renderingStrategy) {
153 Builder<S> b = copy();
154 return b.withRenderingStrategy(renderingStrategy).build();
155 }
156
157 public <S> SqlColumn<S> withParameterTypeConverter(ParameterTypeConverter<S, ?> parameterTypeConverter) {
158 Builder<S> b = copy();
159 return b.withParameterTypeConverter(parameterTypeConverter).build();
160 }
161
162 public <S> SqlColumn<S> withJavaType(Class<S> javaType) {
163 Builder<S> b = copy();
164 return b.withJavaType(javaType).build();
165 }
166
167
168
169
170
171
172
173
174
175
176 @SuppressWarnings("unchecked")
177 private <S> Builder<S> copy() {
178 return new Builder<S>()
179 .withName(this.name)
180 .withTable(this.table)
181 .withJdbcType(this.jdbcType)
182 .withDescendingPhrase(this.descendingPhrase)
183 .withAlias(this.alias)
184 .withTypeHandler(this.typeHandler)
185 .withRenderingStrategy(this.renderingStrategy)
186 .withParameterTypeConverter((ParameterTypeConverter<S, ?>) this.parameterTypeConverter)
187 .withTableQualifier(this.tableQualifier)
188 .withJavaType((Class<S>) this.javaType);
189 }
190
191 public static <T> SqlColumn<T> of(String name, SqlTable table) {
192 return new Builder<T>().withName(name)
193 .withTable(table)
194 .build();
195 }
196
197 public static <T> SqlColumn<T> of(String name, SqlTable table, JDBCType jdbcType) {
198 return new Builder<T>().withName(name)
199 .withTable(table)
200 .withJdbcType(jdbcType)
201 .build();
202 }
203
204 public static class Builder<T> {
205 protected @Nullable String name;
206 protected @Nullable SqlTable table;
207 protected @Nullable JDBCType jdbcType;
208 protected String descendingPhrase = "";
209 protected @Nullable String alias;
210 protected @Nullable String typeHandler;
211 protected @Nullable RenderingStrategy renderingStrategy;
212 protected ParameterTypeConverter<T, ?> parameterTypeConverter = v -> v;
213 protected @Nullable String tableQualifier;
214 protected @Nullable Class<T> javaType;
215
216 public Builder<T> withName(String name) {
217 this.name = name;
218 return this;
219 }
220
221 public Builder<T> withTable(SqlTable table) {
222 this.table = table;
223 return this;
224 }
225
226 public Builder<T> withJdbcType(@Nullable JDBCType jdbcType) {
227 this.jdbcType = jdbcType;
228 return this;
229 }
230
231 public Builder<T> withDescendingPhrase(String descendingPhrase) {
232 this.descendingPhrase = descendingPhrase;
233 return this;
234 }
235
236 public Builder<T> withAlias(@Nullable String alias) {
237 this.alias = alias;
238 return this;
239 }
240
241 public Builder<T> withTypeHandler(@Nullable String typeHandler) {
242 this.typeHandler = typeHandler;
243 return this;
244 }
245
246 public Builder<T> withRenderingStrategy(@Nullable RenderingStrategy renderingStrategy) {
247 this.renderingStrategy = renderingStrategy;
248 return this;
249 }
250
251 public Builder<T> withParameterTypeConverter(ParameterTypeConverter<T, ?> parameterTypeConverter) {
252 this.parameterTypeConverter = parameterTypeConverter;
253 return this;
254 }
255
256 private Builder<T> withTableQualifier(@Nullable String tableQualifier) {
257 this.tableQualifier = tableQualifier;
258 return this;
259 }
260
261 public Builder<T> withJavaType(@Nullable Class<T> javaType) {
262 this.javaType = javaType;
263 return this;
264 }
265
266 public SqlColumn<T> build() {
267 return new SqlColumn<>(this);
268 }
269 }
270 }