|
11 | 11 | import java.time.OffsetDateTime; |
12 | 12 | import java.time.ZoneOffset; |
13 | 13 | import java.util.*; |
| 14 | +import java.util.function.UnaryOperator; |
14 | 15 | import java.util.stream.Collectors; |
15 | 16 |
|
16 | 17 | public class Converter { |
17 | | - private static final Base64.Decoder b64decoder = Base64.getMimeDecoder(); |
18 | | - private static final Base64.Encoder b64encoder = Base64.getMimeEncoder(); |
19 | | - |
20 | 18 | public static final String PSEUDOTYPE_KEY = "$reql_type$"; |
21 | | - |
22 | 19 | public static final String TIME = "TIME"; |
23 | 20 | public static final String GROUPED_DATA = "GROUPED_DATA"; |
24 | 21 | public static final String GEOMETRY = "GEOMETRY"; |
25 | 22 | public static final String BINARY = "BINARY"; |
26 | 23 |
|
27 | | - /* Compact way of keeping these flags around through multiple recursive |
28 | | - passes */ |
29 | | - public static class FormatOptions{ |
| 24 | + /* Compact way of keeping these flags around through multiple recursive passes */ |
| 25 | + public static class FormatOptions { |
30 | 26 | public final boolean rawTime; |
31 | 27 | public final boolean rawGroups; |
32 | 28 | public final boolean rawBinary; |
33 | 29 |
|
34 | | - public FormatOptions(OptArgs args){ |
35 | | - this.rawTime = ((Datum)args.getOrDefault("time_format", |
36 | | - new Datum("native"))).datum.equals("raw"); |
37 | | - this.rawBinary = ((Datum)args.getOrDefault("binary_format", |
38 | | - new Datum("native"))).datum.equals("raw"); |
39 | | - this.rawGroups = ((Datum)args.getOrDefault("group_format", |
40 | | - new Datum("native"))).datum.equals("raw"); |
41 | | - } |
42 | | - } |
| 30 | + public FormatOptions(OptArgs args) { |
| 31 | + Datum time_format = (Datum) args.get("time_format"); |
| 32 | + this.rawTime = time_format != null && "raw".equals(time_format.datum); |
43 | 33 |
|
44 | | - @SuppressWarnings("unchecked") |
45 | | - public static Object convertPseudotypes(Object obj, FormatOptions fmt){ |
46 | | - if(obj instanceof List) { |
47 | | - return ((List<Object>) obj).stream() |
48 | | - .map(item -> convertPseudotypes(item, fmt)) |
49 | | - .collect(Collectors.toList()); |
50 | | - } else if(obj instanceof Map) { |
51 | | - Map<String, Object> mapobj = (Map<String, Object>) obj; |
52 | | - if(mapobj.containsKey(PSEUDOTYPE_KEY)){ |
53 | | - return convertPseudo(mapobj, fmt); |
54 | | - } |
55 | | - return mapobj.entrySet().stream() |
56 | | - .collect( |
57 | | - LinkedHashMap::new, |
58 | | - (map, entry) -> map.put( |
59 | | - entry.getKey(), |
60 | | - convertPseudotypes(entry.getValue(), fmt) |
61 | | - ), |
62 | | - LinkedHashMap<String, Object>::putAll |
63 | | - ); |
64 | | - } else { |
65 | | - return obj; |
| 34 | + Datum binary_format = (Datum) args.get("binary_format"); |
| 35 | + this.rawBinary = binary_format != null && "raw".equals(binary_format.datum); |
| 36 | + |
| 37 | + Datum group_format = (Datum) args.get("group_format"); |
| 38 | + this.rawGroups = group_format != null && "raw".equals(group_format.datum); |
66 | 39 | } |
67 | 40 | } |
68 | 41 |
|
69 | | - public static Object convertPseudo(Map<String, Object> value, FormatOptions fmt) { |
70 | | - if(value == null){ |
71 | | - return null; |
| 42 | + public static Object convertPseudotypes(Object obj, FormatOptions fmt) { |
| 43 | + if (obj instanceof List) { |
| 44 | + return ((List<?>) obj).stream() |
| 45 | + .map(item -> convertPseudotypes(item, fmt)) |
| 46 | + .collect(Collectors.toList()); |
72 | 47 | } |
73 | | - String reqlType = (String) value.get(PSEUDOTYPE_KEY); |
74 | | - switch (reqlType) { |
75 | | - case TIME: |
76 | | - return fmt.rawTime ? value : getTime(value); |
77 | | - case GROUPED_DATA: |
78 | | - return fmt.rawGroups ? value : getGrouped(value); |
79 | | - case BINARY: |
80 | | - return fmt.rawBinary ? value : getBinary(value); |
81 | | - case GEOMETRY: |
82 | | - // Nothing specific here |
83 | | - return value; |
84 | | - default: |
85 | | - // Just leave unknown pseudo-types alone |
86 | | - return value; |
| 48 | + if (obj instanceof Map) { |
| 49 | + Map<?, ?> map = (Map<?, ?>) obj; |
| 50 | + if (map.containsKey(PSEUDOTYPE_KEY)) { |
| 51 | + return handlePseudotypes(map, fmt); |
| 52 | + } |
| 53 | + return map.entrySet().stream().collect( |
| 54 | + LinkedHashMap::new, |
| 55 | + (m, e) -> m.put(e.getKey(), convertPseudotypes(e.getValue(), fmt)), |
| 56 | + LinkedHashMap::putAll |
| 57 | + ); |
87 | 58 | } |
88 | | - } |
89 | 59 |
|
90 | | - @SuppressWarnings("unchecked") |
91 | | - private static List<GroupedResult<?,?>> getGrouped(Map<String, Object> value) { |
92 | | - return ((List<List<Object>>) value.get("data")).stream() |
93 | | - .map(g -> new GroupedResult<>(g.remove(0), g)) |
94 | | - .collect(Collectors.toList()); |
| 60 | + return obj; |
95 | 61 | } |
96 | 62 |
|
97 | | - private static OffsetDateTime getTime(Map<String, Object> obj) { |
98 | | - try { |
99 | | - ZoneOffset offset = ZoneOffset.of((String) obj.get("timezone")); |
100 | | - double epochTime = ((Number) obj.get("epoch_time")).doubleValue(); |
101 | | - Instant timeInstant = Instant.ofEpochMilli(((Double) (epochTime * 1000.0)).longValue()); |
102 | | - return OffsetDateTime.ofInstant(timeInstant, offset); |
103 | | - } catch (Exception ex) { |
104 | | - throw new ReqlDriverError("Error handling date", ex); |
| 63 | + private static Object handlePseudotypes(Map<?, ?> value, FormatOptions fmt) { |
| 64 | + switch ((String) value.get(PSEUDOTYPE_KEY)) { |
| 65 | + case TIME: { |
| 66 | + if (fmt.rawTime) { |
| 67 | + return value; |
| 68 | + } |
| 69 | + try { |
| 70 | + long epochMillis = (long) (((Number) value.get("epoch_time")).doubleValue() * 1000.0); |
| 71 | + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneOffset.of((String) value.get("timezone"))); |
| 72 | + } catch (Exception ex) { |
| 73 | + throw new ReqlDriverError("Error handling date", ex); |
| 74 | + } |
| 75 | + } |
| 76 | + case GROUPED_DATA: { |
| 77 | + if (fmt.rawGroups) { |
| 78 | + return value; |
| 79 | + } |
| 80 | + return ((List<?>) value.get("data")).stream() |
| 81 | + .map(it -> new ArrayList<>((Collection<?>) it)) |
| 82 | + .map(it -> new GroupedResult<>(it.remove(0), it)) |
| 83 | + .collect(Collectors.toList()); |
| 84 | + } |
| 85 | + case BINARY: { |
| 86 | + if (fmt.rawBinary) { |
| 87 | + return value; |
| 88 | + } |
| 89 | + return Base64.getMimeDecoder().decode((String) value.get("data")); |
| 90 | + } |
| 91 | + case GEOMETRY: { |
| 92 | + // Nothing specific here |
| 93 | + return value; |
| 94 | + } |
105 | 95 | } |
| 96 | + return value; |
106 | 97 | } |
107 | 98 |
|
108 | | - private static byte[] getBinary(Map<String, Object> value) { |
109 | | - return b64decoder.decode((String) value.get("data")); |
110 | | - } |
111 | | - |
112 | | - public static Map<String,Object> toBinary(byte[] data){ |
| 99 | + public static Map<String, Object> toBinary(byte[] data) { |
113 | 100 | return new MapObject<String, Object>() |
114 | 101 | .with("$reql_type$", BINARY) |
115 | | - .with("data", b64encoder.encodeToString(data)); |
| 102 | + .with("data", Base64.getEncoder().encodeToString(data)); |
116 | 103 | } |
117 | 104 | } |
0 commit comments