ConverterColumnObject.java
/*
* SPDX-FileCopyrightText: 2025 kaumei.io
* SPDX-License-Identifier: Apache-2.0
*/
package io.kaumei.jdbc.anno.jdbc2java;
import com.palantir.javapoet.CodeBlock;
import io.kaumei.jdbc.anno.gen.TargetMethod;
import io.kaumei.jdbc.anno.model.OptionalFlag;
import io.kaumei.jdbc.anno.model.SQLNameDV;
import io.kaumei.jdbc.anno.store.SearchKey;
import io.kaumei.jdbc.anno.store.SourceDV;
import io.kaumei.jdbc.anno.store.StoreID;
import org.jspecify.annotations.Nullable;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
final class ConverterColumnObject extends Jdbc2JavaConverter {
record Placeholder(TypeMirror type, SourceDV source, ExecutableElement factoryMethod,
SearchKey other) implements Jdbc2JavaConverter.Placeholder {
@Override
public Jdbc2JavaConverter resolve(Map<SearchKey, Jdbc2JavaConverter> converter) {
return new ConverterColumnObject(this, Objects.requireNonNull(converter.get(other)));
}
@Override
public Set<SearchKey> otherPlaceholders() {
return Set.of(other);
}
@Nullable StoreID nonColumnConverter(Map<SearchKey, Jdbc2JavaConverter> converter) {
var result = Objects.requireNonNull(converter.get(other));
if (result.isColumn()) {
return null;
}
return other.toStoreId();
}
}
// ------------------------------------------------------------------------
private final ExecutableElement factoryMethod;
private final Element methodParent;
private final Jdbc2JavaConverter converter;
private ConverterColumnObject(Placeholder placeholder, Jdbc2JavaConverter converter) {
super(placeholder.type, placeholder.source);
this.factoryMethod = placeholder.factoryMethod;
this.methodParent = factoryMethod.getEnclosingElement();
this.converter = converter;
}
// ------------------------------------------------------------------------
@Override
public boolean isColumn() {
return true;
}
@Override
public CodeBlock nullCheck(String varName) {
return CodeBlock.of("$L == null", varName);
}
@Override
public void addColumnByIndex(TargetMethod builder, String localVarName, ColumnIndex index, OptionalFlag optional) {
builder.addComment("ConverterColumnObject.addColumnByIndex", "type", type(), "optional", optional);
var tempVarName = builder.tempVarName(localVarName);
converter.addColumnByIndex(builder, tempVarName, index, OptionalFlag.NULLABLE);
if (optional.isNonNull()) {
builder.beginControlFlow("if($L)", converter.nullCheck(tempVarName));
builder.addThrowColumnWasNull(index);
builder.endControlFlow();
builder.addStatement("var $L = $L", localVarName, createValue(tempVarName));
} else if (optional.isOptionalType()) {
builder.addStatement("$T<$T> $L = $L ? $T.empty() : $T.of($L)",
Optional.class, this.type(),
localVarName, converter.nullCheck(tempVarName),
Optional.class, Optional.class, createValue(tempVarName));
} else {
builder.addStatement("var $L = $L ? null : $L", localVarName, converter.nullCheck(tempVarName), createValue(tempVarName));
}
}
@Override
public void addColumnByName(TargetMethod builder, String localVarName, SQLNameDV columnName, OptionalFlag optional) {
builder.addComment("ConverterColumnObject.addColumnByName", "type", type(), "optional", optional);
var index = ColumnIndex.ofVariable(builder.tempVarName(localVarName), columnName);
builder.addStatement("var $N = rs.findColumn($S)", index.columnIndexVar(), index.columnName());
addColumnByIndex(builder, localVarName, index, optional);
}
private CodeBlock createValue(String varName) {
return switch (this.factoryMethod.getKind()) { // JaCoCo:ignore
case METHOD ->
CodeBlock.of("$T.$N($L)", this.methodParent, this.factoryMethod.getSimpleName(), varName);
case CONSTRUCTOR -> CodeBlock.of("new $L($L)", this.methodParent, varName);
default ->
throw new IllegalStateException("Unexpected kind: " + factoryMethod.getKind()); // sanity-check
};
}
}