001package org.itsallcode.jdbc;
002
003import java.sql.*;
004import java.util.*;
005
006/**
007 * Wrapper for {@link ParameterMetaData} that simplifies usage.
008 * 
009 * @param parameters all parameters
010 */
011public record SimpleParameterMetaData(List<Parameter> parameters) {
012
013    static SimpleParameterMetaData create(final ParameterMetaData parameterMetaData) {
014        return new SimpleParameterMetaData(getParameters(parameterMetaData));
015    }
016
017    private static List<Parameter> getParameters(final ParameterMetaData metaData) {
018        try {
019            final List<Parameter> parameters = new ArrayList<>(metaData.getParameterCount());
020            for (int i = 1; i <= metaData.getParameterCount(); i++) {
021                parameters.add(
022                        new Parameter(metaData.getParameterClassName(i), JDBCType.valueOf(metaData.getParameterType(i)),
023                                metaData.getParameterTypeName(i), ParameterMode.of(metaData.getParameterMode(i)),
024                                metaData.getPrecision(i), metaData.getScale(i), metaData.isSigned(i),
025                                ParameterNullable.of(metaData.isNullable(i))));
026            }
027            return parameters;
028        } catch (final SQLException e) {
029            throw new UncheckedSQLException("Error getting parameter metadata", e);
030        }
031    }
032
033    /**
034     * Parameter type.
035     */
036    public enum ParameterMode {
037        /** Parameter mode IN */
038        IN(ParameterMetaData.parameterModeIn),
039        /** Parameter mode INOUT */
040        INOUT(ParameterMetaData.parameterModeInOut),
041        /** Parameter mode OUT */
042        OUT(ParameterMetaData.parameterModeOut),
043        /** Parameter mode is unknown */
044        UNKNOWN(ParameterMetaData.parameterModeUnknown);
045
046        private final int mode;
047
048        ParameterMode(final int mode) {
049            this.mode = mode;
050        }
051
052        private static ParameterMode of(final int mode) {
053            return Arrays.stream(values())
054                    .filter(m -> m.mode == mode)
055                    .findAny()
056                    .orElseThrow(
057                            () -> new IllegalArgumentException("No parameter mode found for value " + mode));
058        }
059    }
060
061    /**
062     * Parameter nullability status.
063     */
064    public enum ParameterNullable {
065        /** Parameter will not allow {@code NULL} values. */
066        NO_NULLS(ParameterMetaData.parameterNoNulls),
067        /** Parameter will allow {@code NULL} values. */
068        NULLABLE(ParameterMetaData.parameterNullable),
069        /** Parameter nullability status is unknown. */
070        UNKNOWN(ParameterMetaData.parameterNullableUnknown);
071
072        private final int mode;
073
074        ParameterNullable(final int mode) {
075            this.mode = mode;
076        }
077
078        private static ParameterNullable of(final int mode) {
079            return Arrays.stream(values()).filter(m -> m.mode == mode).findAny().orElseThrow(
080                    () -> new IllegalArgumentException("No parameter nullable mode found for value " + mode));
081        }
082    }
083
084    /**
085     * A parameter for a prepared statement.
086     * 
087     * @param className class name of the parameter type
088     * @param type      JDBC type of the parameter
089     * @param typeName  name of the parameter type
090     * @param mode      parameter mode
091     * @param precision parameter precision
092     * @param scale     parameter scale
093     * @param signed    {@code true} if the parameter is signed
094     * @param nullable  nullability of the parameter
095     */
096    public static record Parameter(String className, JDBCType type, String typeName, ParameterMode mode, int precision,
097            int scale, boolean signed, ParameterNullable nullable) {
098    }
099}