/**
   * Returns conversion for converting value of source to target, or returns null if there's no such
   * conversion.
   */
  @NotNull
  private Optional<TypeConversion> findConversionFromDbValue(
      @NotNull Type source, @NotNull Type target) {
    if (isAssignable(target, source)) return Optional.of(TypeConversion.identity());

    Optional<TypeConversion> directConversion =
        typeConversionRegistry.findConversionFromDbValue(source, target);
    if (directConversion.isPresent()) return directConversion;

    Optional<TypeConversion> arrayConversion = findArrayConversion(source, target);
    if (arrayConversion.isPresent()) return arrayConversion;

    Optional<TypeConversion> optionalConversion = findOptionalConversion(source, target);
    if (optionalConversion.isPresent()) return optionalConversion;

    Optional<TypeConversion> enumConversion = findEnumConversion(target);
    if (enumConversion.isPresent()) return enumConversion;

    return Optional.empty();
  }