BindEnumName.java

package net.morimekta.providence.jdbi.v2.annotations;

import net.morimekta.providence.PEnumValue;
import net.morimekta.providence.jdbi.v2.util.NullArgument;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.sqlobject.Binder;
import org.skife.jdbi.v2.sqlobject.BinderFactory;
import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
import org.skife.jdbi.v2.tweak.Argument;

import javax.annotation.Nonnull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;

@Target(value = ElementType.PARAMETER)
@Retention(value = RetentionPolicy.RUNTIME)
@BindingAnnotation(BindEnumName.Factory.class)
public @interface BindEnumName {
    String value();

    class Factory implements BinderFactory<BindEnumName> {
        @Override
        public Binder<BindEnumName, Object> build(BindEnumName bind) {
            return (sqlStatement, annotation, arg) -> {
                if (arg instanceof PEnumValue) {
                    PEnumValue value = (PEnumValue) arg;
                    sqlStatement.bind(annotation.value(), new EnumNameArgument(value));
                } else if (arg == null) {
                    sqlStatement.bind(annotation.value(), new NullArgument(Types.VARCHAR));
                } else {
                    throw new IllegalArgumentException("Not a providence enum value: " + arg.getClass().toString());
                }
            };
        }
    }

    class EnumNameArgument implements Argument {
        private final PEnumValue value;

        EnumNameArgument(@Nonnull PEnumValue value) {
            this.value = value;
        }

        @Override
        public void apply(int position, PreparedStatement statement, StatementContext ctx) throws SQLException {
            statement.setString(position, value.asString());
        }
    }
}