All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mybatis.dynamic.sql.SqlColumn Maven / Gradle / Ivy

The newest version!
/*
 *    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); } } }