org.mybatis.dynamic.sql.SqlColumn Maven / Gradle / Ivy
Show all versions of mybatis-dynamic-sql Show documentation
/*
* Copyright 2016-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mybatis.dynamic.sql;
import java.sql.JDBCType;
import java.util.Objects;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.render.RenderingStrategy;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.StringUtilities;
public class SqlColumn implements BindableColumn, SortSpecification {
protected final String name;
protected final SqlTable table;
protected final JDBCType jdbcType;
protected final boolean isDescending;
protected final String alias;
protected final String typeHandler;
protected final RenderingStrategy renderingStrategy;
protected final ParameterTypeConverter parameterTypeConverter;
protected final String tableQualifier;
protected final Class javaType;
private SqlColumn(Builder builder) {
name = Objects.requireNonNull(builder.name);
table = Objects.requireNonNull(builder.table);
jdbcType = builder.jdbcType;
isDescending = builder.isDescending;
alias = builder.alias;
typeHandler = builder.typeHandler;
renderingStrategy = builder.renderingStrategy;
parameterTypeConverter = Objects.requireNonNull(builder.parameterTypeConverter);
tableQualifier = builder.tableQualifier;
javaType = builder.javaType;
}
public String name() {
return name;
}
public SqlTable table() {
return table;
}
@Override
public Optional jdbcType() {
return Optional.ofNullable(jdbcType);
}
@Override
public Optional alias() {
return Optional.ofNullable(alias);
}
@Override
public Optional typeHandler() {
return Optional.ofNullable(typeHandler);
}
@Override
public Optional> javaType() {
return Optional.ofNullable(javaType);
}
@Override
public Object convertParameterType(T value) {
return parameterTypeConverter.convert(value);
}
@Override
public SortSpecification descending() {
Builder b = copy();
return b.withDescending(true).build();
}
@Override
public SqlColumn as(String alias) {
Builder b = copy();
return b.withAlias(alias).build();
}
/**
* Override the calculated table qualifier if there is one. This is useful for sub-queries
* where the calculated table qualifier may not be correct in all cases.
*
* @param tableQualifier the table qualifier to apply to the rendered column name
* @return a new column that will be rendered with the specified table qualifier
*/
public SqlColumn qualifiedWith(String tableQualifier) {
Builder b = copy();
b.withTableQualifier(tableQualifier);
return b.build();
}
/**
* Set an alias with a camel cased string based on the column name. This can be useful for queries using
* the {@link org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper} where the columns are placed into
* a map based on the column name returned from the database.
*
* A camel case string is mixed case, and most databases do not support unquoted mixed case strings
* as identifiers. Therefore, the generated alias will be surrounded by double quotes thereby making it a
* quoted identifier. Most databases will respect quoted mixed case identifiers.
*
* @return a new column aliased with a camel case version of the column name
*/
public SqlColumn asCamelCase() {
Builder b = copy();
return b.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build(); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public boolean isDescending() {
return isDescending;
}
@Override
public String orderByName() {
return alias().orElse(name);
}
@Override
public FragmentAndParameters render(RenderingContext renderingContext) {
if (tableQualifier == null) {
return FragmentAndParameters.fromFragment(renderingContext.aliasedColumnName(this));
} else {
return FragmentAndParameters.fromFragment(renderingContext.aliasedColumnName(this, tableQualifier));
}
}
@Override
public Optional renderingStrategy() {
return Optional.ofNullable(renderingStrategy);
}
@NotNull
public SqlColumn withTypeHandler(String typeHandler) {
Builder b = copy();
return b.withTypeHandler(typeHandler).build();
}
@NotNull
public SqlColumn withRenderingStrategy(RenderingStrategy renderingStrategy) {
Builder b = copy();
return b.withRenderingStrategy(renderingStrategy).build();
}
@NotNull
public SqlColumn withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) {
Builder b = copy();
return b.withParameterTypeConverter(parameterTypeConverter).build();
}
@NotNull
public SqlColumn withJavaType(Class javaType) {
Builder b = copy();
return b.withJavaType(javaType).build();
}
/**
* This method helps us tell a bit of fiction to the Java compiler. Java, for better or worse,
* does not carry generic type information through chained methods. We want to enable method
* chaining in the "with" methods. With this bit of fiction, we force the compiler to delay type
* inference to the last method in the chain.
*
* @param the type. Will be the same as T for this usage.
* @return a new SqlColumn of type S (S is the same as T)
*/
@SuppressWarnings("unchecked")
private Builder copy() {
return new Builder()
.withName(this.name)
.withTable(this.table)
.withJdbcType(this.jdbcType)
.withDescending(this.isDescending)
.withAlias(this.alias)
.withTypeHandler(this.typeHandler)
.withRenderingStrategy(this.renderingStrategy)
.withParameterTypeConverter((ParameterTypeConverter) this.parameterTypeConverter)
.withTableQualifier(this.tableQualifier)
.withJavaType((Class) this.javaType);
}
public static SqlColumn of(String name, SqlTable table) {
return new Builder().withName(name)
.withTable(table)
.build();
}
public static SqlColumn of(String name, SqlTable table, JDBCType jdbcType) {
return new Builder().withName(name)
.withTable(table)
.withJdbcType(jdbcType)
.build();
}
public static class Builder {
protected String name;
protected SqlTable table;
protected JDBCType jdbcType;
protected boolean isDescending = false;
protected String alias;
protected String typeHandler;
protected RenderingStrategy renderingStrategy;
protected ParameterTypeConverter parameterTypeConverter = v -> v;
protected String tableQualifier;
protected Class javaType;
public Builder withName(String name) {
this.name = name;
return this;
}
public Builder withTable(SqlTable table) {
this.table = table;
return this;
}
public Builder withJdbcType(JDBCType jdbcType) {
this.jdbcType = jdbcType;
return this;
}
public Builder withDescending(boolean isDescending) {
this.isDescending = isDescending;
return this;
}
public Builder withAlias(String alias) {
this.alias = alias;
return this;
}
public Builder withTypeHandler(String typeHandler) {
this.typeHandler = typeHandler;
return this;
}
public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) {
this.renderingStrategy = renderingStrategy;
return this;
}
public Builder withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) {
this.parameterTypeConverter = parameterTypeConverter;
return this;
}
private Builder withTableQualifier(String tableQualifier) {
this.tableQualifier = tableQualifier;
return this;
}
public Builder withJavaType(Class javaType) {
this.javaType = javaType;
return this;
}
public SqlColumn build() {
return new SqlColumn<>(this);
}
}
}