66 */
77package org .elasticsearch .xpack .sql .plugin ;
88
9+ import java .time .ZonedDateTime ;
910import java .util .ArrayList ;
1011import java .util .Arrays ;
12+ import java .util .Collection ;
1113import java .util .List ;
1214import java .util .Set ;
1315import java .util .stream .Collectors ;
1719import org .elasticsearch .test .ESTestCase ;
1820import org .elasticsearch .test .rest .FakeRestRequest ;
1921import org .elasticsearch .xpack .sql .action .SqlQueryResponse ;
22+ import org .elasticsearch .xpack .sql .expression .literal .geo .GeoShape ;
2023import org .elasticsearch .xpack .sql .proto .ColumnInfo ;
2124import org .elasticsearch .xpack .sql .proto .Mode ;
2225
2730import static org .elasticsearch .xpack .sql .plugin .TextFormat .CSV ;
2831import static org .elasticsearch .xpack .sql .plugin .TextFormat .TSV ;
2932import static org .elasticsearch .xpack .sql .proto .SqlVersion .DATE_NANOS_SUPPORT_VERSION ;
33+ import static org .elasticsearch .xpack .sql .type .SqlDataTypes .fromJava ;
3034
3135public class TextFormatTests extends ESTestCase {
3236
@@ -152,6 +156,151 @@ public void testInvalidCsvDelims() {
152156 }
153157 }
154158
159+ public void testCsvMultiValueEmpty () {
160+ String text = CSV .format (req (), withData (singletonList (singletonList (emptyList ()))));
161+ assertEquals ("null_column\r \n []\r \n " , text );
162+ }
163+
164+ public void testTsvMultiValueEmpty () {
165+ String text = TSV .format (req (), withData (singletonList (singletonList (emptyList ()))));
166+ assertEquals ("null_column\n []\n " , text );
167+ }
168+
169+ public void testCsvMultiValueNull () {
170+ String text = CSV .format (req (), withData (singletonList (singletonList (singletonList (null )))));
171+ assertEquals ("null_column\r \n [NULL]\r \n " , text );
172+ }
173+
174+ public void testTsvMultiValueNull () {
175+ String text = TSV .format (req (), withData (singletonList (singletonList (asList (null , null )))));
176+ assertEquals ("null_column\n [NULL,NULL]\n " , text );
177+ }
178+
179+ public void testCsvMultiValueKeywords () {
180+ String text = CSV .format (req (), withData (singletonList (singletonList (asList ("one" , "two" , "one, two" )))));
181+ assertEquals ("keyword_column\r \n \" [\" \" one\" \" ,\" \" two\" \" ,\" \" one, two\" \" ]\" \r \n " , text );
182+ }
183+
184+ public void testTsvMultiValueKeywords () {
185+ String text = TSV .format (req (), withData (singletonList (singletonList (asList ("one" , "two" , "one, two" )))));
186+ assertEquals ("keyword_column\n [\" one\" ,\" two\" ,\" one, two\" ]\n " , text );
187+ }
188+
189+ public void testCsvMultiValueKeywordWithQuote () {
190+ String text = CSV .format (req (), withData (singletonList (singletonList (asList ("one" , "two" , "one\" two" )))));
191+ assertEquals ("keyword_column\r \n \" [\" \" one\" \" ,\" \" two\" \" ,\" \" one\\ \" \" two\" \" ]\" \r \n " , text );
192+ }
193+
194+ public void testTsvMultiValueKeywordWithQuote () {
195+ String text = TSV .format (req (), withData (singletonList (singletonList (asList ("one" , "two" , "one\" two" )))));
196+ assertEquals ("keyword_column\n [\" one\" ,\" two\" ,\" one\\ \" two\" ]\n " , text );
197+ }
198+
199+ public void testTsvMultiValueKeywordWithTab () {
200+ String text = TSV .format (req (), withData (singletonList (singletonList (asList ("one" , "two" , "one\t two" )))));
201+ assertEquals ("keyword_column\n [\" one\" ,\" two\" ,\" one\\ ttwo\" ]\n " , text );
202+ }
203+
204+ public void testCsvMultiValueKeywordTwoColumns () {
205+ String text = CSV .format (req (), withData (singletonList (asList (asList ("one" , "two" , "three" ), asList ("4" , "5" )))));
206+ assertEquals ("keyword_column,keyword_column\r \n \" [\" \" one\" \" ,\" \" two\" \" ,\" \" three\" \" ]\" ,\" [\" \" 4\" \" ,\" \" 5\" \" ]\" \r \n " , text );
207+ }
208+
209+ public void testTsvMultiValueKeywordTwoColumns () {
210+ String text = TSV .format (req (), withData (singletonList (asList (asList ("one" , "two" , "three" ), asList ("4" , "5" )))));
211+ assertEquals ("keyword_column\t keyword_column\n [\" one\" ,\" two\" ,\" three\" ]\t [\" 4\" ,\" 5\" ]\n " , text );
212+ }
213+
214+ public void testCsvMultiValueBooleans () {
215+ String text = CSV .format (req (), withData (singletonList (singletonList (asList (true , false , true )))));
216+ assertEquals ("boolean_column\r \n \" [true,false,true]\" \r \n " , text );
217+ }
218+
219+ public void testTsvMultiValueBooleans () {
220+ String text = TSV .format (req (), withData (singletonList (singletonList (asList (true , false , true )))));
221+ assertEquals ("boolean_column\n [true,false,true]\n " , text );
222+ }
223+
224+ public void testCsvMultiValueIntegers () {
225+ String text = CSV .format (req (), withData (singletonList (asList (
226+ asList ((byte ) 1 , (byte ) 2 ), asList ((short ) 3 , (short ) 4 ), asList (5 , 6 ), asList (7L , 8L )
227+ ))));
228+ assertEquals ("byte_column,short_column,integer_column,long_column\r \n \" [1,2]\" ,\" [3,4]\" ,\" [5,6]\" ,\" [7,8]\" \r \n " , text );
229+ }
230+
231+ public void testTsvMultiValueIntegers () {
232+ String text = TSV .format (req (), withData (singletonList (asList (
233+ asList ((byte ) 1 , (byte ) 2 ), asList ((short ) 3 , (short ) 4 ), asList (5 , 6 ), asList (7L , 8L )
234+ ))));
235+ assertEquals ("byte_column\t short_column\t integer_column\t long_column\n [1,2]\t [3,4]\t [5,6]\t [7,8]\n " , text );
236+ }
237+
238+ public void testCsvMultiValueFloatingPoints () {
239+ String text = CSV .format (req (), withData (singletonList (asList (asList (1.1f , 2.2f ), asList (3.3d , 4.4d )))));
240+ assertEquals ("float_column,double_column\r \n \" [1.1,2.2]\" ,\" [3.3,4.4]\" \r \n " , text );
241+ }
242+
243+ public void testTsvMultiValueFloatingPoints () {
244+ String text = TSV .format (req (), withData (singletonList (asList (asList (1.1f , 2.2f ), asList (3.3d , 4.4d )))));
245+ assertEquals ("float_column\t double_column\n [1.1,2.2]\t [3.3,4.4]\n " , text );
246+ }
247+
248+ public void testCsvMultiValueDates () {
249+ String date1 = "2020-02-02T02:02:02.222+03:00" ;
250+ String date2 = "1969-01-23T23:34:56.123456789+13:30" ;
251+ String text = CSV .format (req (), withData (singletonList (singletonList (
252+ asList (ZonedDateTime .parse (date1 ), ZonedDateTime .parse (date2 ))
253+ ))));
254+ assertEquals ("datetime_column\r \n \" [" + date1 + "," + date2 + "]\" \r \n " , text );
255+ }
256+
257+ public void testTsvMultiValueDates () {
258+ String date1 = "2020-02-02T02:02:02.222+03:00" ;
259+ String date2 = "1969-01-23T23:34:56.123456789+13:30" ;
260+ String text = TSV .format (req (), withData (singletonList (singletonList (
261+ asList (ZonedDateTime .parse (date1 ), ZonedDateTime .parse (date2 ))
262+ ))));
263+ assertEquals ("datetime_column\n [" + date1 + "," + date2 + "]\n " , text );
264+ }
265+
266+ public void testCsvMultiValueGeoPoints () {
267+ GeoShape point1 = new GeoShape (12.34 , 56.78 );
268+ double lat = randomDouble (), lon = randomDouble ();
269+ GeoShape point2 = new GeoShape (lat , lon );
270+ String text = CSV .format (req (), withData (singletonList (singletonList (asList (point1 , point2 )))));
271+ assertEquals ("geo_shape_column\r \n \" [POINT (12.34 56.78),POINT (" + lat + " " + lon + ")]\" \r \n " , text );
272+ }
273+
274+ public void testTsvMultiValueGeoPoints () {
275+ GeoShape point1 = new GeoShape (12.34 , 56.78 );
276+ double lat = randomDouble (), lon = randomDouble ();
277+ GeoShape point2 = new GeoShape (lat , lon );
278+ String text = TSV .format (req (), withData (singletonList (singletonList (asList (point1 , point2 )))));
279+ assertEquals ("geo_shape_column\n [POINT (12.34 56.78),POINT (" + lat + " " + lon + ")]\n " , text );
280+ }
281+
282+ public void testCsvMultiValueSingletons () {
283+ String text = CSV .format (req (), withData (singletonList (asList (emptyList (), singletonList (false ), singletonList ("string" ),
284+ singletonList (1 ), singletonList (2. ), singletonList (new GeoShape (12.34 , 56.78 ))))));
285+ assertEquals ("null_column,boolean_column,keyword_column,integer_column,double_column,geo_shape_column\r \n " +
286+ "[],[false],\" [\" \" string\" \" ]\" ,[1],[2.0],[POINT (12.34 56.78)]\r \n " , text );
287+ }
288+
289+ public void testCsvMultiValueWithDelimiter () {
290+ String text = CSV .format (reqWithParam ("delimiter" , String .valueOf ("|" )),
291+ withData (singletonList (asList (emptyList (), asList (null , null ), asList (false , true ), asList ("string" , "strung" ),
292+ asList (1 , 2 ), asList (3.3 , 4. ), asList (new GeoShape (12.34 , 56.78 ), new GeoShape (90 , 10 ))))));
293+ assertEquals ("null_column|null_column|boolean_column|keyword_column|integer_column|double_column|geo_shape_column\r \n " +
294+ "[]|[NULL,NULL]|[false,true]|\" [\" \" string\" \" ,\" \" strung\" \" ]\" |[1,2]|[3.3,4.0]|[POINT (12.34 56.78),POINT (90.0 10.0)]\r \n " ,
295+ text );
296+ }
297+
298+ public void testTsvMultiValueSingletons () {
299+ String text = TSV .format (req (), withData (singletonList (asList (emptyList (), singletonList (false ), singletonList ("string" ),
300+ singletonList (1 ), singletonList (2. ), singletonList (new GeoShape (12.34 , 56.78 ))))));
301+ assertEquals ("null_column\t boolean_column\t keyword_column\t integer_column\t double_column\t geo_shape_column\n " +
302+ "[]\t [false]\t [\" string\" ]\t [1]\t [2.0]\t [POINT (12.34 56.78)]\n " , text );
303+ }
155304
156305 private static SqlQueryResponse emptyData () {
157306 return new SqlQueryResponse (
@@ -164,6 +313,24 @@ private static SqlQueryResponse emptyData() {
164313 );
165314 }
166315
316+ private static SqlQueryResponse withData (List <List <Object >> rows ) {
317+ List <ColumnInfo > headers = new ArrayList <>();
318+ if (rows .isEmpty () == false ) {
319+ // headers
320+ for (Object o : rows .get (0 )) {
321+ if (o instanceof Collection ) {
322+ Collection <?> col = (Collection <?>) o ;
323+ o = col .isEmpty () ? null : col .toArray ()[0 ];
324+ }
325+
326+ String typeName = fromJava (o ).typeName ();
327+ headers .add (new ColumnInfo ("index" , typeName + "_column" , typeName + "_array" ));
328+ }
329+ }
330+
331+ return new SqlQueryResponse (null , Mode .JDBC , DATE_NANOS_SUPPORT_VERSION , false , headers , rows );
332+ }
333+
167334 private static SqlQueryResponse regularData () {
168335 // headers
169336 List <ColumnInfo > headers = new ArrayList <>();
0 commit comments