Metadata merge(Metadata other) {
        List<MappingField> fields = new ArrayList<>(concat(this.fields.stream(), other.fields.stream())
                .collect(toCollection(() -> new TreeSet<>(Comparator.comparing(MappingField::name)))));
        Map<String, String> options = concat(this.options.entrySet().stream(), other.options.entrySet().stream())
                .collect(LinkedHashMap::new, (map, entry) -> map.putIfAbsent(entry.getKey(), entry.getValue()), Map::putAll);
        return new Metadata(fields, options);
    }
@Test
    public void test_merge() {
        Metadata first = new Metadata(
                asList(
                        new MappingField("field1", QueryDataType.INT, "__key.field1"),
                        new MappingField("field2", QueryDataType.INT, "__key.field2")
                ),
                ImmutableMap.of("key1", "1", "key2", "2")
        );
        Metadata second = new Metadata(
                asList(
                        new MappingField("field2", QueryDataType.VARCHAR, "this.field2"),
                        new MappingField("field3", QueryDataType.VARCHAR, "this.field3")
                ),
                ImmutableMap.of("key2", "two", "key3", "three")
        );

        Metadata merged = first.merge(second);
        assertThat(merged).isEqualToComparingFieldByField(new Metadata(
                asList(
                        new MappingField("field1", QueryDataType.INT, "__key.field1"),
                        new MappingField("field2", QueryDataType.INT, "__key.field2"),
                        new MappingField("field3", QueryDataType.VARCHAR, "this.field3")
                ),
                ImmutableMap.of("key1", "1", "key2", "2", "key3", "three")
        ));
    }