Fauna .NET Driver 0.1.0-beta
 
Loading...
Searching...
No Matches
DynamicDeserializer.cs
Go to the documentation of this file.
1using Fauna.Mapping;
2using Fauna.Types;
3
4namespace Fauna.Serialization;
5
6internal class DynamicDeserializer : BaseDeserializer<object?>
7{
8 public static DynamicDeserializer Singleton { get; } = new();
9
10 private readonly ListDeserializer<object?> _list;
11 private readonly PageDeserializer<object?> _page;
12 private readonly DictionaryDeserializer<object?> _dict;
13
14 private DynamicDeserializer()
15 {
16 _list = new ListDeserializer<object?>(this);
17 _page = new PageDeserializer<object?>(this);
18 _dict = new DictionaryDeserializer<object?>(this);
19 }
20
21 public override object? Deserialize(MappingContext context, ref Utf8FaunaReader reader) =>
22 reader.CurrentTokenType switch
23 {
24 TokenType.StartObject => _dict.Deserialize(context, ref reader),
25 TokenType.StartArray => _list.Deserialize(context, ref reader),
26 TokenType.StartPage => _page.Deserialize(context, ref reader),
27 TokenType.StartRef => DeserializeRef(context, ref reader),
28 TokenType.StartDocument => DeserializeDocument(context, ref reader),
29 TokenType.String => reader.GetString(),
30 TokenType.Int => reader.GetInt(),
31 TokenType.Long => reader.GetLong(),
32 TokenType.Double => reader.GetDouble(),
33 TokenType.Date => reader.GetDate(),
34 TokenType.Time => reader.GetTime(),
35 TokenType.True or TokenType.False => reader.GetBoolean(),
36 TokenType.Module => reader.GetModule(),
37 TokenType.Null => null,
38 _ => throw new SerializationException(
39 $"Unexpected token while deserializing: {reader.CurrentTokenType}"),
40 };
41
42 private object DeserializeRef(MappingContext context, ref Utf8FaunaReader reader)
43 {
44 string? id = null;
45 string? name = null;
46 Module? coll = null;
47 var exists = true;
48 string? cause = null;
49 var allProps = new Dictionary<string, object?>();
50
51 while (reader.Read() && reader.CurrentTokenType != TokenType.EndRef)
52 {
53 if (reader.CurrentTokenType != TokenType.FieldName)
54 throw new SerializationException(
55 $"Unexpected token while deserializing into DocumentRef: {reader.CurrentTokenType}");
56
57 var fieldName = reader.GetString()!;
58 reader.Read();
59 switch (fieldName)
60 {
61 case "id":
62 id = reader.GetString();
63 allProps["id"] = id;
64 break;
65 case "name":
66 name = reader.GetString();
67 allProps["name"] = name;
68 break;
69 case "coll":
70 coll = reader.GetModule();
71 allProps["coll"] = coll;
72 break;
73 case "exists":
74 exists = reader.GetBoolean();
75 allProps["exists"] = exists;
76 break;
77 case "cause":
78 cause = reader.GetString();
79 allProps["cause"] = cause;
80 break;
81 default:
82 allProps[fieldName] = DynamicDeserializer.Singleton.Deserialize(context, ref reader);
83 break;
84 }
85 }
86
87 if (id != null && coll != null)
88 {
89 if (exists)
90 {
91 return new DocumentRef(id, coll);
92 }
93
94 return new NullDocumentRef(id, coll, cause!);
95 }
96
97 if (name != null && coll != null)
98 {
99 if (exists)
100 {
101 return new NamedDocumentRef(name, coll);
102 }
103
104 return new NullNamedDocumentRef(name, coll, cause!);
105 }
106
107 // Unsupported ref type, but don't fail for forward compatibility.
108 return allProps;
109 }
110
111 private object DeserializeDocument(MappingContext context, ref Utf8FaunaReader reader)
112 {
113 var data = new Dictionary<string, object?>();
114 string? id = null;
115 string? name = null;
116 DateTime? ts = null;
117 Module? coll = null;
118
119 while (reader.Read() && reader.CurrentTokenType != TokenType.EndDocument)
120 {
121 if (reader.CurrentTokenType != TokenType.FieldName)
122 throw new SerializationException(
123 $"Unexpected token while deserializing into Document: {reader.CurrentTokenType}");
124
125 var fieldName = reader.GetString()!;
126 reader.Read();
127 switch (fieldName)
128 {
129 case "id":
130 id = reader.GetString();
131 break;
132 case "name":
133 name = reader.GetString();
134 break;
135 case "coll":
136 coll = reader.GetModule();
137
138 // if we encounter a mapped collection, jump to the class deserializer.
139 // NB this relies on the fact that docs on the wire always
140 // start with id and coll.
141 if (context.TryGetCollection(coll.Name, out var collInfo))
142 {
143 return collInfo.Deserializer.DeserializeDocument(context, id, name, ref reader);
144 }
145
146 break;
147 case "ts":
148 ts = reader.GetTime();
149 break;
150 default:
151 data[fieldName] = DynamicDeserializer.Singleton.Deserialize(context, ref reader);
152 break;
153 }
154 }
155
156 if (id != null && coll != null && ts != null)
157 {
158 if (name != null) data["name"] = name;
159 return new Document(id, coll, ts.GetValueOrDefault(), data);
160 }
161
162 if (name != null && coll != null && ts != null)
163 {
164 return new NamedDocument(name, coll, ts.GetValueOrDefault(), data);
165 }
166
167 // Unsupported document type, but don't fail for forward compatibility.
168 if (id != null) data["id"] = id;
169 if (name != null) data["name"] = name;
170 if (coll != null) data["coll"] = coll;
171 if (ts != null) data["ts"] = ts;
172 return data;
173 }
174}
bool TryGetCollection(string col, [NotNullWhen(true)] out MappingInfo? ret)
T Deserialize(MappingContext context, ref Utf8FaunaReader reader)
Represents a document.
Definition Document.cs:7
Represents a document ref.
Definition DocumentRef.cs:7
Represents a module, a singleton object grouping related functionalities. Modules are serialized as @...
Definition Module.cs:8
string Name
Gets the name of the module. The name is used to identify and reference the module.
Definition Module.cs:12
Represents a document that has a "name" instead of an "id". For example, a Role document is represent...
Represents a document ref that has a "name" instead of an "id". For example, a Role document referenc...
Represents a null reference to a document, including a reason for its null state.
Represents a reference to a named document that is null, including a reason for its null state....
TokenType
Enumerates the types of tokens used in Fauna serialization.
Definition TokenType.cs:7