3131import org .elasticsearch .xcontent .XContentBuilder ;
3232import org .elasticsearch .xpack .esql .core .querydsl .query .MatchAll ;
3333import org .elasticsearch .xpack .esql .core .querydsl .query .RangeQuery ;
34+ import org .elasticsearch .xpack .esql .core .querydsl .query .TermQuery ;
3435import org .elasticsearch .xpack .esql .core .tree .Source ;
3536
3637import java .io .IOException ;
@@ -46,12 +47,14 @@ interface Setup {
4647 XContentBuilder mapping (XContentBuilder builder ) throws IOException ;
4748
4849 List <List <Object >> build (RandomIndexWriter iw ) throws IOException ;
50+
51+ boolean useSyntheticSourceDelegate ();
4952 }
5053
5154 @ ParametersFactory
5255 public static List <Object []> params () {
5356 List <Object []> params = new ArrayList <>();
54- for (String fieldType : new String [] { "long" , "integer" , "short" , "byte" , "double" , "float" , "keyword" }) {
57+ for (String fieldType : new String [] { "long" , "integer" , "short" , "byte" , "double" , "float" , "keyword" , "text" }) {
5558 for (boolean multivaluedField : new boolean [] { true , false }) {
5659 for (boolean allowEmpty : new boolean [] { true , false }) {
5760 params .add (new Object [] { new StandardSetup (fieldType , multivaluedField , allowEmpty , 100 ) });
@@ -69,54 +72,66 @@ public SingleValueQueryTests(Setup setup) {
6972 }
7073
7174 public void testMatchAll () throws IOException {
72- testCase (new SingleValueQuery (new MatchAll (Source .EMPTY ), "foo" , false ).asBuilder (), this ::runCase );
75+ testCase (new SingleValueQuery (new MatchAll (Source .EMPTY ), "foo" , setup . useSyntheticSourceDelegate () ).asBuilder (), this ::runCase );
7376 }
7477
7578 public void testMatchSome () throws IOException {
7679 int max = between (1 , 100 );
7780 testCase (
78- new SingleValueQuery .Builder (new RangeQueryBuilder ("i" ).lt (max ), "foo" , Source .EMPTY ),
81+ new SingleValueQuery (
82+ new RangeQuery (Source .EMPTY , "i" , null , false , max , false , randomZone ()),
83+ "foo" ,
84+ setup .useSyntheticSourceDelegate ()
85+ ).asBuilder (),
7986 (fieldValues , count ) -> runCase (fieldValues , count , null , max )
8087 );
8188 }
8289
8390 public void testSubPhrase () throws IOException {
84- testCase (new SingleValueQuery .Builder (new MatchPhraseQueryBuilder ("str" , "fox jumped" ), "foo" , Source .EMPTY ), this ::runCase );
91+ SingleValueQuery .AbstractBuilder builder = setup .useSyntheticSourceDelegate ()
92+ ? new SingleValueQuery .SyntheticSourceDelegateBuilder (new MatchPhraseQueryBuilder ("str" , "fox jumped" ), "foo" , Source .EMPTY )
93+ : new SingleValueQuery .Builder (new MatchPhraseQueryBuilder ("str" , "fox jumped" ), "foo" , Source .EMPTY );
94+ testCase (builder , this ::runCase );
8595 }
8696
8797 public void testMatchNone () throws IOException {
8898 testCase (
89- new SingleValueQuery . Builder (new MatchNoneQueryBuilder () , "foo" , Source . EMPTY ),
99+ new SingleValueQuery (new MatchAll ( Source . EMPTY ). negate ( Source . EMPTY ) , "foo" , setup . useSyntheticSourceDelegate ()). asBuilder ( ),
90100 (fieldValues , count ) -> assertThat (count , equalTo (0 ))
91101 );
92102 }
93103
94104 public void testRewritesToMatchNone () throws IOException {
95105 testCase (
96- new SingleValueQuery . Builder (new TermQueryBuilder ( "missing" , 0 ), "foo" , Source . EMPTY ),
106+ new SingleValueQuery (new TermQuery ( Source . EMPTY , "missing" , 0 ), "foo" , setup . useSyntheticSourceDelegate ()). asBuilder ( ),
97107 (fieldValues , count ) -> assertThat (count , equalTo (0 ))
98108 );
99109 }
100110
101111 public void testNotMatchAll () throws IOException {
102112 testCase (
103- new SingleValueQuery (new MatchAll (Source .EMPTY ), "foo" , false ).negate (Source .EMPTY ).asBuilder (),
113+ new SingleValueQuery (new MatchAll (Source .EMPTY ), "foo" , setup . useSyntheticSourceDelegate () ).negate (Source .EMPTY ).asBuilder (),
104114 (fieldValues , count ) -> assertThat (count , equalTo (0 ))
105115 );
106116 }
107117
108118 public void testNotMatchNone () throws IOException {
109119 testCase (
110- new SingleValueQuery (new MatchAll (Source .EMPTY ).negate (Source .EMPTY ), "foo" , false ).negate (Source .EMPTY ).asBuilder (),
120+ new SingleValueQuery (new MatchAll (Source .EMPTY ).negate (Source .EMPTY ), "foo" , setup .useSyntheticSourceDelegate ()).negate (
121+ Source .EMPTY
122+ ).asBuilder (),
111123 this ::runCase
112124 );
113125 }
114126
115127 public void testNotMatchSome () throws IOException {
116128 int max = between (1 , 100 );
117129 testCase (
118- new SingleValueQuery (new RangeQuery (Source .EMPTY , "i" , null , false , max , false , null ), "foo" , false ).negate (Source .EMPTY )
119- .asBuilder (),
130+ new SingleValueQuery (
131+ new RangeQuery (Source .EMPTY , "i" , null , false , max , false , null ),
132+ "foo" ,
133+ setup .useSyntheticSourceDelegate ()
134+ ).negate (Source .EMPTY ).asBuilder (),
120135 (fieldValues , count ) -> runCase (fieldValues , count , max , 100 )
121136 );
122137 }
@@ -186,7 +201,13 @@ private record StandardSetup(String fieldType, boolean multivaluedField, boolean
186201 public XContentBuilder mapping (XContentBuilder builder ) throws IOException {
187202 builder .startObject ("i" ).field ("type" , "long" ).endObject ();
188203 builder .startObject ("str" ).field ("type" , "text" ).endObject ();
189- return builder .startObject ("foo" ).field ("type" , fieldType ).endObject ();
204+ builder .startObject ("foo" ).field ("type" , fieldType );
205+ if (fieldType .equals ("text" )) {
206+ builder .startObject ("fields" );
207+ builder .startObject ("raw" ).field ("type" , "keyword" ).field ("ignore_above" , 256 ).endObject ();
208+ builder .endObject ();
209+ }
210+ return builder .endObject ();
190211 }
191212
192213 @ Override
@@ -200,6 +221,11 @@ public List<List<Object>> build(RandomIndexWriter iw) throws IOException {
200221 return fieldValues ;
201222 }
202223
224+ @ Override
225+ public boolean useSyntheticSourceDelegate () {
226+ return fieldType .equals ("text" );
227+ }
228+
203229 private List <Object > values (int i ) {
204230 // i == 10 forces at least one multivalued field when we're configured for multivalued fields
205231 boolean makeMultivalued = multivaluedField && (i == 10 || randomBoolean ());
@@ -226,7 +252,7 @@ private Object randomValue() {
226252 case "byte" -> randomByte ();
227253 case "double" -> randomDouble ();
228254 case "float" -> randomFloat ();
229- case "keyword" -> randomAlphaOfLength (5 );
255+ case "keyword" , "text" -> randomAlphaOfLength (5 );
230256 default -> throw new UnsupportedOperationException ();
231257 };
232258 }
@@ -253,6 +279,12 @@ private List<IndexableField> docFor(int i, Iterable<Object> values) {
253279 fields .add (new KeywordField ("foo" , v .toString (), Field .Store .NO ));
254280 }
255281 }
282+ case "text" -> {
283+ for (Object v : values ) {
284+ fields .add (new TextField ("foo" , v .toString (), Field .Store .NO ));
285+ fields .add (new KeywordField ("foo.raw" , v .toString (), Field .Store .NO ));
286+ }
287+ }
256288 default -> throw new UnsupportedOperationException ();
257289 }
258290 return fields ;
@@ -280,5 +312,10 @@ public List<List<Object>> build(RandomIndexWriter iw) throws IOException {
280312 }
281313 return fieldValues ;
282314 }
315+
316+ @ Override
317+ public boolean useSyntheticSourceDelegate () {
318+ return randomBoolean ();
319+ }
283320 }
284321}
0 commit comments