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

org.babyfish.jimmer.sql.runtime.EnumProviderBuilder Maven / Gradle / Ivy

There is a newer version: 0.9.19
Show newest version
package org.babyfish.jimmer.sql.runtime;

import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class EnumProviderBuilder, S> {

    private final Class enumType;

    private final Class sqlType;

    private final Function defaultSqlValueMapper;

    private final Map sqlMap = new HashMap<>();

    public static , S> EnumProviderBuilder of(
            Class enumType,
            Class sqlType,
            Function defaultSqlValueMapper
    ) {
        return new EnumProviderBuilder<>(enumType, sqlType, defaultSqlValueMapper);
    }

    private EnumProviderBuilder(
            Class enumType,
            Class sqlType,
            Function defaultSqlValueMapper
    ) {
        this.enumType = enumType;
        this.sqlType = sqlType;
        this.defaultSqlValueMapper = defaultSqlValueMapper;
    }

    public EnumProviderBuilder map(@NotNull E enumValue, @NotNull S sqlValue) {
        if (sqlMap.containsValue(enumValue)) {
            throw new IllegalStateException("'${enumValue}' has been mapped");
        }
        sqlMap.put(enumValue, sqlValue);
        return this;
    }

    public EnumProvider build() {
        Map sqlMap = new HashMap<>(this.sqlMap);
        for (E enumValue : enumType.getEnumConstants()) {
            sqlMap.computeIfAbsent(enumValue, defaultSqlValueMapper);
        }
        Map enumMap = new HashMap<>();
        for (Map.Entry entry : sqlMap.entrySet()) {
            E conflictEnum = enumMap.put(entry.getValue(), entry.getKey());
            if (conflictEnum != null) {
                throw new IllegalStateException(
                        "Both '" +
                                entry.getKey() +
                                "' and '" +
                                conflictEnum +
                                "' are mapped as '" +
                                entry.getValue() +
                                "'"
                );
            }
        }
        return new EnumProvider<>(
                enumType,
                sqlType,
                enumMap,
                sqlMap
        );
    }

    private static class EnumProvider, S> extends AbstractScalarProvider {

        private final Map enumMap;

        private final Map sqlMap;

        public EnumProvider(
                Class enumType,
                Class sqlType,
                Map enumMap,
                Map sqlMap
        ) {
            super(enumType, sqlType);
            this.enumMap = enumMap;
            this.sqlMap = sqlMap;
        }

        @Override
        public @NotNull E toScalar(@NotNull S sqlValue) {
            E scalarValue = enumMap.get(sqlValue);
            if (scalarValue == null) {
                throw new IllegalArgumentException(
                        "Cannot resolve '" +
                                getScalarType() +
                                "' by the value '" +
                                sqlValue +
                                "'"
                );
            }
            return scalarValue;
        }

        @Override
        public @NotNull S toSql(@NotNull E enumValue) {
            S sqlValue = sqlMap.get(enumValue);
            if (sqlValue == null) {
                throw new AssertionError(
                        "Internal bug: Enum can be converted to sql value absolutely"
                );
            }
            return sqlValue;
        }
    }
}