Fauna v10 .NET/C# Driver 0.2.0-beta
 
Loading...
Searching...
No Matches
DocumentSerializer.cs
Go to the documentation of this file.
2using Fauna.Mapping;
3using Fauna.Types;
4
5namespace Fauna.Serialization;
6
7internal class DocumentSerializer<T> : BaseSerializer<T> where T : class
8{
9
10 public override T Deserialize(MappingContext context, ref Utf8FaunaReader reader)
11 {
12 return reader.CurrentTokenType switch
13 {
14 TokenType.StartDocument => DeserializeDocument(context, ref reader),
15 TokenType.StartRef => DeserializeRef(context, ref reader),
16 _ => throw new SerializationException(
17 $"Unexpected token while deserializing into {typeof(NullableDocument<T>)}: {reader.CurrentTokenType}")
18 };
19 }
20
21 public override void Serialize(MappingContext context, Utf8FaunaWriter writer, object? o)
22 {
23 DynamicSerializer.Singleton.Serialize(context, writer, o);
24 }
25
26 private T DeserializeDocument(MappingContext context, ref Utf8FaunaReader reader)
27 {
28 var data = new Dictionary<string, object?>();
29 string? id = null;
30 object? name = null;
31 DateTime? ts = null;
32 Module? coll = null;
33
34 while (reader.Read() && reader.CurrentTokenType != TokenType.EndDocument)
35 {
36 if (reader.CurrentTokenType != TokenType.FieldName)
37 throw new SerializationException(
38 $"Unexpected token while deserializing into Document: {reader.CurrentTokenType}");
39
40 var fieldName = reader.GetString()!;
41 reader.Read();
42 switch (fieldName)
43 {
44 case "id":
45 id = reader.GetString();
46 break;
47 case "name":
48 name = DynamicSerializer.Singleton.Deserialize(context, ref reader);
49 break;
50 case "coll":
51 coll = reader.GetModule();
52
53 // if we encounter a mapped collection, jump to the class deserializer.
54 // NB this relies on the fact that docs on the wire always
55 // start with id and coll.
56 if (context.TryGetCollection(coll.Name, out var info))
57 {
58 // If the user asks for a different type, don't use the saved deserializer.
59 if (info.Type == typeof(T) || typeof(object) == typeof(T))
60 {
61 if (info.ClassSerializer is IClassDocumentSerializer ser)
62 {
63 // This assumes ordering on the wire. If name is not null and we're here, then it's a named document so name is a string.
64 string? nm = name != null ? (string)name : null;
65 return (ser.DeserializeDocument(context, id, nm, ref reader) as T)!;
66 }
67 }
68 }
69
70 break;
71 case "ts":
72 ts = reader.GetTime();
73 break;
74 default:
75 data[fieldName] = DynamicSerializer.Singleton.Deserialize(context, ref reader);
76 break;
77 }
78 }
79
80 if (id != null && coll != null && ts != null)
81 {
82 // For convenience, if a user asks for a DocumentRef but gets a document, give them the ref.
83 if (typeof(Ref) == typeof(T))
84 {
85 return (new Ref(id, coll) as T)!;
86 }
87
88 // For convenience, if a user asks for a NullableDocument<DocumentRef> but gets a document, give it to them.
89 if (typeof(NullableDocument<Ref>) == typeof(T))
90 {
91 var docRef = new Ref(id, coll);
92 return (new NonNullDocument<Ref>(docRef) as T)!;
93 }
94
95 if (name != null) data["name"] = name;
96
97 var doc = new Document(id, coll, ts.GetValueOrDefault(), data);
98 if (typeof(Document) == typeof(T))
99 {
100 return (doc as T)!;
101 }
102
103 return (new NonNullDocument<Document>(doc) as T)!;
104 }
105
106 if (name != null && coll != null && ts != null)
107 {
108 // If we're here, name is a string.
109 var nameAsString = (string)name;
110 var r = new NamedDocument(nameAsString, coll, ts.GetValueOrDefault(), data);
111 if (r is T d) return d;
113 if (nr is T nnd) return nnd;
114
115 // For convenience, if a user asks for a NamedDocumentRef but gets a named document, give them the ref.
116 if (typeof(NamedRef) == typeof(T))
117 {
118 return (new NamedRef(nameAsString, coll) as T)!;
119 }
120
121 // For convenience, if a user asks for a NullableDocument<NamedDocumentRef> but gets a named document, give it to them.
122 if (typeof(NullableDocument<NamedRef>) == typeof(T))
123 {
124 var docRef = new NamedRef(nameAsString, coll);
125 return (new NonNullDocument<NamedRef>(docRef) as T)!;
126 }
127
128 var doc = new NamedDocument(nameAsString, coll, ts.GetValueOrDefault(), data);
129 if (typeof(NamedDocument) == typeof(T))
130 {
131 return (doc as T)!;
132 }
133
134 return (new NonNullDocument<NamedDocument>(doc) as T)!;
135 }
136
137 throw new SerializationException("Unsupported document type.");
138 }
139
140 private T DeserializeRef(MappingContext context, ref Utf8FaunaReader reader)
141 {
142 string? id = null;
143 string? name = null;
144 Module? coll = null;
145 string? cause = null;
146 var exists = true;
147
148 while (reader.Read() && reader.CurrentTokenType != TokenType.EndRef)
149 {
150 if (reader.CurrentTokenType != TokenType.FieldName)
151 throw new SerializationException(
152 $"Unexpected token while deserializing into DocumentRef: {reader.CurrentTokenType}");
153
154 var fieldName = reader.GetString()!;
155 reader.Read();
156 switch (fieldName)
157 {
158 case "id":
159 id = reader.GetString();
160 break;
161 case "name":
162 name = reader.GetString();
163 break;
164 case "coll":
165 coll = reader.GetModule();
166 break;
167 case "cause":
168 cause = reader.GetString();
169 break;
170 case "exists":
171 exists = reader.GetBoolean();
172 break;
173 }
174 }
175
176 if (id != null && coll != null && exists)
177 {
178 var docRef = new Ref(id, coll);
179 if (typeof(NullableDocument<Ref>) == typeof(T))
180 {
181 return (new NonNullDocument<Ref>(docRef) as T)!;
182 }
183
184 return (docRef as T)!;
185 }
186
187 if (name != null && coll != null && exists)
188 {
189 var docRef = new NamedRef(name, coll);
190 if (typeof(NullableDocument<NamedRef>) == typeof(T))
191 {
192 return (new NonNullDocument<NamedRef>(docRef) as T)!;
193 }
194
195 return (docRef as T)!;
196 }
197
198 if (id != null && coll != null && !exists)
199 {
200 if (typeof(Ref) == typeof(T) || typeof(Document) == typeof(T))
201 {
202 throw new NullDocumentException(id, coll, cause!);
203 }
204
205 if (typeof(NullableDocument<Ref>) == typeof(T))
206 {
207 return (new NullDocument<Ref>(id, coll, cause!) as T)!;
208 }
209
210 return (new NullDocument<Document>(id, coll, cause!) as T)!;
211 }
212
213 if (name != null && coll != null && !exists)
214 {
215 if (typeof(NamedRef) == typeof(T) || typeof(NamedDocument) == typeof(T))
216 {
217 throw new NullDocumentException(name, coll, cause!);
218 }
219
220 if (typeof(NullableDocument<NamedRef>) == typeof(T))
221 {
222 return (new NullDocument<NamedRef>(name, coll, cause!) as T)!;
223 }
224
225 return (new NullDocument<NamedDocument>(name, coll, cause!) as T)!;
226 }
227
228
229 throw new SerializationException("Unsupported reference type");
230 }
231
232}
A class representing the mapping context to be used during serialization and deserialization.
bool TryGetCollection(string col, [NotNullWhen(true)] out MappingInfo? ret)
Gets the MappingInfo for a given collection name.
Represents a document.
Definition Document.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...
Definition NamedRef.cs:8
A class wrapping a non-null document returned by Fauna.
A class representing a null document returned by Fauna.
A wrapper class that allows Document and user-defined classes to be null references.
Represents a document ref.
Definition Ref.cs:7
TokenType
Enumerates the types of tokens used in Fauna serialization.
Definition TokenType.cs:7