public List<MappingField> resolveAndValidateFields(
            List<MappingField> userFields,
            Map<String, String> options,
            NodeEngine nodeEngine
    ) {
        final InternalSerializationService serializationService = (InternalSerializationService) nodeEngine
                .getSerializationService();
        final AbstractRelationsStorage relationsStorage = ((CalciteSqlOptimizer) nodeEngine.getSqlService().getOptimizer())
                .relationsStorage();
        // normalize and validate the names and external names
        for (MappingField field : userFields) {
            String name = field.name();

            String externalName = field.externalName();
            if (externalName == null) {
                if (name.equals(KEY) || name.equals(VALUE)) {
                    externalName = name;
                } else {
                    externalName = VALUE_PREFIX + name;
                }
                field.setExternalName(name);
            }

            if ((name.equals(KEY) && !externalName.equals(KEY))
                    || (name.equals(VALUE) && !externalName.equals(VALUE))) {
                throw QueryException.error("Cannot rename field: '" + name + '\'');
            }

            if (!EXT_NAME_PATTERN.matcher(externalName).matches()) {
                throw QueryException.error("Invalid external name: " + externalName);
            }
        }

        Stream<MappingField> keyFields = resolveAndValidateFields(true, userFields, options,
                serializationService, relationsStorage);
        Stream<MappingField> valueFields = resolveAndValidateFields(false, userFields, options,
                serializationService, relationsStorage);

        Map<String, MappingField> fields = Stream.concat(keyFields, valueFields)
                .collect(LinkedHashMap::new, (map, field) -> map.putIfAbsent(field.name(), field), Map::putAll);

        if (fields.isEmpty()) {
            throw QueryException.error("The resolved field list is empty");
        }
        return new ArrayList<>(fields.values());
    }
@Test
    public void when_valueFieldsEmpty_then_doesNotFail() {
        Map<String, String> options = ImmutableMap.of(
                OPTION_KEY_FORMAT, JAVA_FORMAT,
                OPTION_VALUE_FORMAT, JAVA_FORMAT
        );
        given(resolver.resolveAndValidateFields(eq(true), eq(emptyList()), eq(options), eq(ss)))
                .willReturn(Stream.of(field("__key", QueryDataType.INT)));
        given(resolver.resolveAndValidateFields(eq(false), eq(emptyList()), eq(options), eq(ss)))
                .willReturn(Stream.empty());

        List<MappingField> fields = resolvers.resolveAndValidateFields(emptyList(), options, nodeEngine);
        assertThat(fields).containsExactly(field("__key", QueryDataType.INT));
    }