class IndexNameResolver {

    private IndexNameResolver() {
    }

    public static Supplier<String> create(RelationName relationName,
                                          @Nullable String partitionIdent,
                                          @Nullable List<Input<?>> partitionedByInputs) {
        if (partitionIdent == null && (partitionedByInputs == null || partitionedByInputs.isEmpty())) {
            return forTable(relationName);
        }
        if (partitionIdent == null) {
            return forPartition(relationName, partitionedByInputs);
        }
        return forPartition(relationName, partitionIdent);
    }

    public static Supplier<String> forTable(final RelationName relationName) {
        return relationName::indexNameOrAlias;
    }

    private static Supplier<String> forPartition(RelationName relationName, String partitionIdent) {
        return () -> IndexParts.toIndexName(relationName, partitionIdent);
    }

    private static Supplier<String> forPartition(final RelationName relationName, final List<Input<?>> partitionedByInputs) {<FILL_FUNCTION_BODY>}
}

        assert partitionedByInputs.size() > 0 : "must have at least 1 partitionedByInput";
        final LoadingCache<List<String>, String> cache = Caffeine.newBuilder()
            .executor(Runnable::run)
            .initialCapacity(10)
            .maximumSize(20)
            .build(new CacheLoader<List<String>, String>() {
                @Override
                public String load(@NotNull List<String> key) {
                    return IndexParts.toIndexName(relationName, PartitionName.encodeIdent(key));
                }
            });
        return () -> {
            // copy because the values of the inputs are mutable
            List<String> partitions = Lists.map(partitionedByInputs, input -> nullOrString(input.value()));
            return cache.get(partitions);
        };
    
<no_super_class>