-
-
Notifications
You must be signed in to change notification settings - Fork 138
/
Converter.cs
201 lines (175 loc) · 6.68 KB
/
Converter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using RethinkDb.Driver.Ast;
using RethinkDb.Driver.Model;
namespace RethinkDb.Driver.Net
{
public class Converter
{
public const string PseudoTypeKey = "$reql_type$";
public const string Time = "TIME";
public const string GroupedData = "GROUPED_DATA";
public const string Geometry = "GEOMETRY";
public const string Binary = "BINARY";
public static JToken ConvertPesudoTypes(JToken data, FormatOptions fmt)
{
var reqlTypes = data.SelectTokens("$..$reql_type$").ToList();
foreach( var typeToken in reqlTypes )
{
var reqlType = typeToken.Value<string>();
//JObject -> JProerty -> JVaule:$reql_type$, go backup the chain.
var pesudoObject = typeToken.Parent.Parent as JObject;
JToken convertedValue = null;
if( reqlType == Time )
{
if( fmt.RawTime )
continue;
convertedValue = new JValue(GetTime(pesudoObject));
}
else if( reqlType == GroupedData )
{
if( fmt.RawGroups )
continue;
convertedValue = new JValue(GetGrouped(pesudoObject));
}
else if( reqlType == Binary )
{
if( fmt.RawBinary )
continue;
convertedValue = pesudoObject["data"];
}
else if( reqlType == Geometry )
{
// Nothing specific here
continue;
}
else
{
// Just leave unknown pseudo-types alone
continue;
}
pesudoObject.Replace(convertedValue);
}
return data;
}
private static DateTimeOffset GetTime(JObject value)
{
double epoch_time = value["epoch_time"].ToObject<double>();
string timezone = value["timezone"].ToString();
var tz = TimeSpan.Parse(timezone.Substring(1));
if( !timezone.StartsWith("+") )
tz = -tz;
var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); // epoch UTC
var dt = epoch + TimeSpan.FromSeconds(epoch_time);
return dt.ToOffset(tz);
}
private static byte[] GetBinary(JObject value)
{
var base64 = value["data"].Value<string>();
return Convert.FromBase64String(base64);
}
private static List<GroupedResult> GetGrouped(JObject value)
{
return value["data"].ToObject<List<List<object>>>()
.Select(g =>
{
var group = g[0];
g.RemoveAt(0);
return new GroupedResult(group, g);
}).ToList();
}
public static object ToBinary(byte[] data)
{
var mob = new MapObject();
mob.with(PseudoTypeKey, Binary);
mob.with("data", Convert.ToBase64String(data));
return mob;
}
public static Func<object, JObject> PocoConverter = DefaultPocoConverter;
public static JObject DefaultPocoConverter(object value)
{
return JObject.FromObject(value, JsonSerializer.CreateDefault(new JsonSerializerSettings()
{
Converters = new[] {TimeConverter, BinaryConverter}
}));
}
public static JsonConverter TimeConverter = new PocoIso8601Converter();
public static JsonConverter BinaryConverter = new PocoBinaryConverter();
}
public class PocoIso8601Converter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var ast = Util.ToReqlAst(value);
serializer.Serialize(writer, ast.Build());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime) ||
objectType == typeof(DateTimeOffset);
}
}
public class PocoBinaryConverter :
#if DNX
JsonConverter
#else
BinaryConverter
#endif
{
private bool useInternal = false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartObject(); //convert to $reql_type$
writer.WritePropertyName(Converter.PseudoTypeKey);
writer.WriteValue(Converter.Binary);
writer.WritePropertyName("data");
if( useInternal )
{
#if !DNX
base.WriteJson(writer, value, serializer);
#endif
}
else
{
writer.WriteValue(value);
}
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
#if !DNX
useInternal = base.CanConvert(objectType);
#endif
return useInternal || objectType == typeof(byte[]);
}
}
public class FormatOptions
{
public bool RawTime { get; }
public bool RawGroups { get; }
public bool RawBinary { get; }
public FormatOptions(OptArgs args)
{
// TODO: find a better way to do this.
ReqlAst datum;
var value = args.TryGetValue("time_format", out datum) ? ((Datum)datum).datum : new Datum("native").datum;
this.RawTime = value.Equals("raw");
value = args.TryGetValue("binary_format", out datum) ? ((Datum)datum).datum : new Datum("native").datum;
this.RawBinary = value.Equals("raw");
value = args.TryGetValue("group_format", out datum) ? ((Datum)datum).datum : new Datum("native").datum;
this.RawGroups = value.Equals("raw");
}
}
}