3030import com .fasterxml .jackson .core .JsonProcessingException ;
3131import com .fasterxml .jackson .databind .ObjectMapper ;
3232import com .google .common .collect .ImmutableMap ;
33+ import java .time .DateTimeException ;
3334import java .time .Instant ;
35+ import java .time .LocalDate ;
36+ import java .time .LocalDateTime ;
37+ import java .time .LocalTime ;
3438import java .time .format .DateTimeParseException ;
39+ import java .time .temporal .TemporalAccessor ;
3540import java .util .ArrayList ;
3641import java .util .LinkedHashMap ;
3742import java .util .List ;
3843import java .util .Map ;
3944import java .util .Optional ;
40- import java .util .function .Function ;
45+ import java .util .function .BiFunction ;
4146import lombok .Getter ;
4247import lombok .Setter ;
48+ import org .apache .logging .log4j .LogManager ;
4349import org .opensearch .common .time .DateFormatters ;
4450import org .opensearch .sql .data .model .ExprBooleanValue ;
4551import org .opensearch .sql .data .model .ExprByteValue ;
6167import org .opensearch .sql .opensearch .data .utils .Content ;
6268import org .opensearch .sql .opensearch .data .utils .ObjectContent ;
6369import org .opensearch .sql .opensearch .data .utils .OpenSearchJsonContent ;
70+ import org .opensearch .sql .opensearch .mapping .MappingEntry ;
6471import org .opensearch .sql .opensearch .response .agg .OpenSearchAggregationResponseParser ;
6572
6673/**
@@ -73,6 +80,9 @@ public class OpenSearchExprValueFactory {
7380 @ Setter
7481 private Map <String , ExprType > typeMapping ;
7582
83+
84+ private Map <String , MappingEntry > typeMapping2 ;
85+
7686 @ Getter
7787 @ Setter
7888 private OpenSearchAggregationResponseParser parser ;
@@ -81,26 +91,26 @@ public class OpenSearchExprValueFactory {
8191
8292 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
8393
84- private final Map <ExprType , Function <Content , ExprValue >> typeActionMap =
85- new ImmutableMap .Builder <ExprType , Function <Content , ExprValue >>()
86- .put (INTEGER , c -> new ExprIntegerValue (c .intValue ()))
87- .put (LONG , c -> new ExprLongValue (c .longValue ()))
88- .put (SHORT , c -> new ExprShortValue (c .shortValue ()))
89- .put (BYTE , c -> new ExprByteValue (c .byteValue ()))
90- .put (FLOAT , c -> new ExprFloatValue (c .floatValue ()))
91- .put (DOUBLE , c -> new ExprDoubleValue (c .doubleValue ()))
92- .put (STRING , c -> new ExprStringValue (c .stringValue ()))
93- .put (BOOLEAN , c -> ExprBooleanValue .of (c .booleanValue ()))
94+ private final Map <ExprType , BiFunction <Content , MappingEntry , ExprValue >> typeActionMap =
95+ new ImmutableMap .Builder <ExprType , BiFunction <Content , MappingEntry , ExprValue >>()
96+ .put (INTEGER , ( c , m ) -> new ExprIntegerValue (c .intValue ()))
97+ .put (LONG , ( c , m ) -> new ExprLongValue (c .longValue ()))
98+ .put (SHORT , ( c , m ) -> new ExprShortValue (c .shortValue ()))
99+ .put (BYTE , ( c , m ) -> new ExprByteValue (c .byteValue ()))
100+ .put (FLOAT , ( c , m ) -> new ExprFloatValue (c .floatValue ()))
101+ .put (DOUBLE , ( c , m ) -> new ExprDoubleValue (c .doubleValue ()))
102+ .put (STRING , ( c , m ) -> new ExprStringValue (c .stringValue ()))
103+ .put (BOOLEAN , ( c , m ) -> ExprBooleanValue .of (c .booleanValue ()))
94104 .put (TIMESTAMP , this ::parseTimestamp )
95- .put (DATE , c -> new ExprDateValue (parseTimestamp (c ).dateValue ().toString ()))
96- .put (TIME , c -> new ExprTimeValue (parseTimestamp (c ).timeValue ().toString ()))
97- .put (DATETIME , c -> new ExprDatetimeValue (parseTimestamp (c ).datetimeValue ()))
98- .put (OPENSEARCH_TEXT , c -> new OpenSearchExprTextValue (c .stringValue ()))
99- .put (OPENSEARCH_TEXT_KEYWORD , c -> new OpenSearchExprTextKeywordValue (c .stringValue ()))
100- .put (OPENSEARCH_IP , c -> new OpenSearchExprIpValue (c .stringValue ()))
101- .put (OPENSEARCH_GEO_POINT , c -> new OpenSearchExprGeoPointValue (c .geoValue ().getLeft (),
105+ .put (DATE , ( c , m ) -> new ExprDateValue (parseTimestamp (c , m ).dateValue ().toString ()))
106+ .put (TIME , ( c , m ) -> new ExprTimeValue (parseTimestamp (c , m ).timeValue ().toString ()))
107+ .put (DATETIME , ( c , m ) -> new ExprDatetimeValue (parseTimestamp (c , m ).datetimeValue ()))
108+ .put (OPENSEARCH_TEXT , ( c , m ) -> new OpenSearchExprTextValue (c .stringValue ()))
109+ .put (OPENSEARCH_TEXT_KEYWORD , ( c , m ) -> new OpenSearchExprTextKeywordValue (c .stringValue ()))
110+ .put (OPENSEARCH_IP , ( c , m ) -> new OpenSearchExprIpValue (c .stringValue ()))
111+ .put (OPENSEARCH_GEO_POINT , ( c , m ) -> new OpenSearchExprGeoPointValue (c .geoValue ().getLeft (),
102112 c .geoValue ().getRight ()))
103- .put (OPENSEARCH_BINARY , c -> new OpenSearchExprBinaryValue (c .stringValue ()))
113+ .put (OPENSEARCH_BINARY , ( c , m ) -> new OpenSearchExprBinaryValue (c .stringValue ()))
104114 .build ();
105115
106116 /**
@@ -111,6 +121,12 @@ public OpenSearchExprValueFactory(
111121 this .typeMapping = typeMapping ;
112122 }
113123
124+ public OpenSearchExprValueFactory (Map <String , ExprType > typeMapping ,
125+ Map <String , MappingEntry > typeMapping2 ) {
126+ this .typeMapping = typeMapping ;
127+ this .typeMapping2 = typeMapping2 ;
128+ }
129+
114130 /**
115131 * The struct construction has the following assumption. 1. The field has OpenSearch Object
116132 * data type. https://www.elastic.co/guide/en/elasticsearch/reference/current/object.html 2. The
@@ -151,7 +167,7 @@ private ExprValue parse(Content content, String field, Optional<ExprType> fieldT
151167 return parseArray (content , field );
152168 } else {
153169 if (typeActionMap .containsKey (type )) {
154- return typeActionMap .get (type ).apply (content );
170+ return typeActionMap .get (type ).apply (content , typeMapping2 . getOrDefault ( field , null ) );
155171 } else {
156172 throw new IllegalStateException (
157173 String .format (
@@ -188,11 +204,61 @@ private ExprValue constructTimestamp(String value) {
188204 }
189205 }
190206
191- private ExprValue parseTimestamp (Content value ) {
207+ // returns java.time.format.Parsed
208+ private TemporalAccessor parseTimestampString (String value , MappingEntry mapping ) {
209+ if (mapping == null ) {
210+ return null ;
211+ }
212+ for (var formatter : mapping .getRegularFormatters ()) {
213+ try {
214+ return formatter .parse (value );
215+ } catch (Exception ignored ) {
216+ // nothing to do, try another format
217+ }
218+ }
219+ for (var formatter : mapping .getNamedFormatters ()) {
220+ try {
221+ return formatter .parse (value );
222+ } catch (Exception ignored ) {
223+ // nothing to do, try another format
224+ }
225+ }
226+ return null ;
227+ }
228+
229+ private ExprValue parseTimestamp (Content value , MappingEntry mapping ) {
192230 if (value .isNumber ()) {
193231 return new ExprTimestampValue (Instant .ofEpochMilli (value .longValue ()));
194232 } else if (value .isString ()) {
195- return constructTimestamp (value .stringValue ());
233+ TemporalAccessor parsed = parseTimestampString (value .stringValue (), mapping );
234+ if (parsed == null ) { // failed to parse or no formats given
235+ return constructTimestamp (value .stringValue ());
236+ }
237+ try {
238+ return new ExprTimestampValue (Instant .from (parsed ));
239+ } catch (DateTimeException ignored ) {
240+ // nothing to do, try another type
241+ }
242+ // TODO return not ExprTimestampValue
243+ try {
244+ return new ExprTimestampValue (new ExprDateValue (LocalDate .from (parsed )).timestampValue ());
245+ } catch (DateTimeException ignored ) {
246+ // nothing to do, try another type
247+ }
248+ try {
249+ return new ExprTimestampValue (new ExprDatetimeValue (LocalDateTime .from (parsed )).timestampValue ());
250+ } catch (DateTimeException ignored ) {
251+ // nothing to do, try another type
252+ }
253+ try {
254+ return new ExprTimestampValue (new ExprTimeValue (LocalTime .from (parsed )).timestampValue ());
255+ } catch (DateTimeException ignored ) {
256+ // nothing to do, try another type
257+ }
258+ // TODO throw exception
259+ LogManager .getLogger (OpenSearchExprValueFactory .class ).error (
260+ String .format ("Can't recognize parsed value: %s, %s" , parsed , parsed .getClass ()));
261+ return new ExprStringValue (value .stringValue ());
196262 } else {
197263 return new ExprTimestampValue ((Instant ) value .objectValue ());
198264 }
0 commit comments