|
32 | 32 | import org.elasticsearch.xcontent.XContentType;
|
33 | 33 | import org.elasticsearch.xcontent.json.JsonXContent;
|
34 | 34 | import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
|
| 35 | +import org.elasticsearch.xpack.esql.core.type.DataType; |
35 | 36 | import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
|
36 | 37 | import org.hamcrest.Matcher;
|
37 | 38 | import org.junit.Before;
|
|
45 | 46 | import java.util.List;
|
46 | 47 | import java.util.Locale;
|
47 | 48 | import java.util.Map;
|
| 49 | +import java.util.Objects; |
48 | 50 | import java.util.TreeMap;
|
49 | 51 | import java.util.function.Function;
|
| 52 | +import java.util.stream.Collectors; |
50 | 53 |
|
51 | 54 | import static org.elasticsearch.test.ListMatcher.matchesList;
|
52 | 55 | import static org.elasticsearch.test.MapMatcher.assertMap;
|
@@ -690,7 +693,7 @@ public void testByteFieldWithIntSubfieldTooBig() throws IOException {
|
690 | 693 | * </pre>.
|
691 | 694 | */
|
692 | 695 | public void testIncompatibleTypes() throws IOException {
|
693 |
| - assumeOriginalTypesReported(); |
| 696 | + assumeSuggestedCastReported(); |
694 | 697 | keywordTest().createIndex("test1", "f");
|
695 | 698 | index("test1", """
|
696 | 699 | {"f": "f1"}""");
|
@@ -764,7 +767,7 @@ public void testDistinctInEachIndex() throws IOException {
|
764 | 767 | * </pre>.
|
765 | 768 | */
|
766 | 769 | public void testMergeKeywordAndObject() throws IOException {
|
767 |
| - assumeOriginalTypesReported(); |
| 770 | + assumeSuggestedCastReported(); |
768 | 771 | keywordTest().createIndex("test1", "file");
|
769 | 772 | index("test1", """
|
770 | 773 | {"file": "f1"}""");
|
@@ -959,7 +962,7 @@ public void testIntegerDocValuesConflict() throws IOException {
|
959 | 962 | * In an ideal world we'd promote the {@code integer} to an {@code long} and just go.
|
960 | 963 | */
|
961 | 964 | public void testLongIntegerConflict() throws IOException {
|
962 |
| - assumeOriginalTypesReported(); |
| 965 | + assumeSuggestedCastReported(); |
963 | 966 | longTest().sourceMode(SourceMode.DEFAULT).createIndex("test1", "emp_no");
|
964 | 967 | index("test1", """
|
965 | 968 | {"emp_no": 1}""");
|
@@ -1002,7 +1005,7 @@ public void testLongIntegerConflict() throws IOException {
|
1002 | 1005 | * In an ideal world we'd promote the {@code short} to an {@code integer} and just go.
|
1003 | 1006 | */
|
1004 | 1007 | public void testIntegerShortConflict() throws IOException {
|
1005 |
| - assumeOriginalTypesReported(); |
| 1008 | + assumeSuggestedCastReported(); |
1006 | 1009 | intTest().sourceMode(SourceMode.DEFAULT).createIndex("test1", "emp_no");
|
1007 | 1010 | index("test1", """
|
1008 | 1011 | {"emp_no": 1}""");
|
@@ -1051,7 +1054,7 @@ public void testIntegerShortConflict() throws IOException {
|
1051 | 1054 | * </pre>.
|
1052 | 1055 | */
|
1053 | 1056 | public void testTypeConflictInObject() throws IOException {
|
1054 |
| - assumeOriginalTypesReported(); |
| 1057 | + assumeSuggestedCastReported(); |
1055 | 1058 | createIndex("test1", empNoInObject("integer"));
|
1056 | 1059 | index("test1", """
|
1057 | 1060 | {"foo": {"emp_no": 1}}""");
|
@@ -1379,6 +1382,12 @@ private void assumeOriginalTypesReported() throws IOException {
|
1379 | 1382 | assumeTrue("This test makes sense for versions that report original types", requiredClusterCapability);
|
1380 | 1383 | }
|
1381 | 1384 |
|
| 1385 | + private void assumeSuggestedCastReported() throws IOException { |
| 1386 | + var capsName = EsqlCapabilities.Cap.SUGGESTED_CAST.name().toLowerCase(Locale.ROOT); |
| 1387 | + boolean requiredClusterCapability = clusterHasCapability("POST", "/_query", List.of(), List.of(capsName)).orElse(false); |
| 1388 | + assumeTrue("This test makes sense for versions that report suggested casts", requiredClusterCapability); |
| 1389 | + } |
| 1390 | + |
1382 | 1391 | private CheckedConsumer<XContentBuilder, IOException> empNoInObject(String empNoType) {
|
1383 | 1392 | return index -> {
|
1384 | 1393 | index.startObject("properties");
|
@@ -1715,7 +1724,23 @@ private static Map<String, Object> columnInfo(String name, String type) {
|
1715 | 1724 | }
|
1716 | 1725 |
|
1717 | 1726 | private static Map<String, Object> unsupportedColumnInfo(String name, String... originalTypes) {
|
1718 |
| - return Map.of("name", name, "type", "unsupported", "original_types", List.of(originalTypes)); |
| 1727 | + DataType suggested = DataType.suggestedCast( |
| 1728 | + List.of(originalTypes).stream().map(DataType::fromTypeName).filter(Objects::nonNull).collect(Collectors.toSet()) |
| 1729 | + ); |
| 1730 | + if (suggested == null) { |
| 1731 | + return Map.of("name", name, "type", "unsupported", "original_types", List.of(originalTypes)); |
| 1732 | + } else { |
| 1733 | + return Map.of( |
| 1734 | + "name", |
| 1735 | + name, |
| 1736 | + "type", |
| 1737 | + "unsupported", |
| 1738 | + "original_types", |
| 1739 | + List.of(originalTypes), |
| 1740 | + "suggested_cast", |
| 1741 | + suggested.typeName() |
| 1742 | + ); |
| 1743 | + } |
1719 | 1744 | }
|
1720 | 1745 |
|
1721 | 1746 | private static void index(String name, String... docs) throws IOException {
|
|
0 commit comments