Fauna v10 .NET/C# Driver 1.0.0
 
Loading...
Searching...
No Matches
Serializer.cs
Go to the documentation of this file.
1using System.Runtime.CompilerServices;
2using Fauna.Mapping;
3using Fauna.Types;
4
5namespace Fauna.Serialization;
6
10public static class Serializer
11{
15 public static ISerializer<object?> Dynamic => DynamicSerializer.Singleton;
16
17 private static readonly Dictionary<Type, ISerializer> _reg = new();
18
19 internal static readonly HashSet<string> Tags = new()
20 {
21 "@int", "@long", "@double", "@date", "@time", "@mod", "@stream", "@ref", "@doc", "@set", "@object", "@bytes"
22 };
23
24 private static readonly DynamicSerializer s_object = DynamicSerializer.Singleton;
25 private static readonly StringSerializer s_string = new();
26 private static readonly ByteSerializer s_byte = new();
27 private static readonly BytesSerializer s_bytes = new();
28 private static readonly SByteSerializer s_sbyte = new();
29 private static readonly ShortSerializer s_short = new();
30 private static readonly UShortSerializer s_ushort = new();
31 private static readonly IntSerializer s_int = new();
32 private static readonly UIntSerializer s_uint = new();
33 private static readonly LongSerializer s_long = new();
34 private static readonly FloatSerializer s_float = new();
35 private static readonly DoubleSerializer s_double = new();
36 private static readonly DateOnlySerializer s_dateOnly = new();
37 private static readonly DateTimeSerializer s_dateTime = new();
38 private static readonly DateTimeOffsetSerializer s_dateTimeOffset = new();
39 private static readonly BooleanSerializer s_bool = new();
40 private static readonly ModuleSerializer s_module = new();
41 private static readonly EventSourceSerializer s_eventSource = new();
42 private static readonly QuerySerializer s_query = new();
43 private static readonly QueryExprSerializer s_queryExpr = new();
44 private static readonly QueryLiteralSerializer s_queryLiteral = new();
45 private static readonly QueryArrSerializer s_queryArr = new();
46 private static readonly QueryObjSerializer s_queryObj = new();
47 private static readonly QueryValSerializer s_queryVal = new();
48
49
56 public static ISerializer<T> Generate<T>(MappingContext context) where T : notnull
57 {
58 var targetType = typeof(T);
59 var ser = (ISerializer<T>)Generate(context, targetType);
60 return ser;
61 }
62
69 public static ISerializer Generate(MappingContext context, Type targetType)
70 {
71 if (_reg.TryGetValue(targetType, out var s)) return s;
72
73 if (IsAnonymousType(targetType))
74 {
75 var info = context.GetInfo(targetType);
76 return info.ClassSerializer;
77 }
78
79 if (targetType == typeof(object)) return s_object;
80 if (targetType == typeof(string)) return s_string;
81 if (targetType == typeof(byte)) return s_byte;
82 if (targetType == typeof(byte[])) return s_bytes;
83 if (targetType == typeof(sbyte)) return s_sbyte;
84 if (targetType == typeof(short)) return s_short;
85 if (targetType == typeof(ushort)) return s_ushort;
86 if (targetType == typeof(int)) return s_int;
87 if (targetType == typeof(uint)) return s_uint;
88 if (targetType == typeof(long)) return s_long;
89 if (targetType == typeof(float)) return s_float;
90 if (targetType == typeof(double)) return s_double;
91 if (targetType == typeof(DateOnly)) return s_dateOnly;
92 if (targetType == typeof(DateTime)) return s_dateTime;
93 if (targetType == typeof(DateTimeOffset)) return s_dateTimeOffset;
94 if (targetType == typeof(bool)) return s_bool;
95 if (targetType == typeof(Module)) return s_module;
96 if (targetType == typeof(EventSource)) return s_eventSource;
97 if (targetType == typeof(Query)) return s_query;
98 if (targetType == typeof(QueryExpr)) return s_queryExpr;
99 if (targetType == typeof(QueryLiteral)) return s_queryLiteral;
100 if (targetType == typeof(QueryArr)) return s_queryArr;
101 if (targetType == typeof(QueryObj)) return s_queryObj;
102 if (targetType == typeof(QueryVal)) return s_queryVal;
103
104 if (targetType.IsGenericType)
105 {
106 if (targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
107 {
108 var args = targetType.GetGenericArguments();
109 if (args.Length == 1)
110 {
111 var inner = (ISerializer)Generate(context, args[0]);
112 var serType = typeof(NullableStructSerializer<>).MakeGenericType(new[] { args[0] });
113 object? ser = Activator.CreateInstance(serType, new[] { inner });
114
115 return (ISerializer)ser!;
116 }
117
118 throw new ArgumentException($"Unsupported nullable type. Generic arguments > 1: {args}");
119 }
120
121
122 if (targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
123 {
124 var argTypes = targetType.GetGenericArguments();
125 var keyType = argTypes[0];
126 var valueType = argTypes[1];
127
128 if (keyType != typeof(string))
129 throw new ArgumentException(
130 $"Unsupported Dictionary key type. Key must be of type string, but was a {keyType}");
131
132 var valueSerializer = Generate(context, valueType);
133
134 var serType = typeof(DictionarySerializer<>).MakeGenericType(new[] { valueType });
135 object? ser = Activator.CreateInstance(serType, new[] { valueSerializer });
136
137 return (ISerializer)ser!;
138 }
139
140 if (targetType.GetGenericTypeDefinition() == typeof(List<>) || targetType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
141 {
142 var elemType = targetType.GetGenericArguments()[0];
143 var elemSerializer = Generate(context, elemType);
144
145 var serType = typeof(ListSerializer<>).MakeGenericType(new[] { elemType });
146 object? ser = Activator.CreateInstance(serType, new[] { elemSerializer });
147
148 return (ISerializer)ser!;
149 }
150
151 if (targetType.GetGenericTypeDefinition() == typeof(Page<>))
152 {
153 var elemType = targetType.GetGenericArguments()[0];
154 var elemSerializer = Generate(context, elemType);
155
156 var serType = typeof(PageSerializer<>).MakeGenericType(new[] { elemType });
157 object? ser = Activator.CreateInstance(serType, new[] { elemSerializer });
158
159 return (ISerializer)ser!;
160 }
161
162 if (targetType.GetGenericTypeDefinition() == typeof(BaseRef<>))
163 {
164 var docType = targetType.GetGenericArguments()[0];
165 var docSerializer = Generate(context, docType);
166
167 var serType = typeof(BaseRefSerializer<>).MakeGenericType(new[] { docType });
168 object? ser = Activator.CreateInstance(serType, new[] { docSerializer });
169
170 return (ISerializer)ser!;
171 }
172
173 if (targetType.GetGenericTypeDefinition() == typeof(Ref<>))
174 {
175 var docType = targetType.GetGenericArguments()[0];
176 var docSerializer = Generate(context, docType);
177
178 var serType = typeof(RefSerializer<>).MakeGenericType(new[] { docType });
179 object? ser = Activator.CreateInstance(serType, new[] { docSerializer });
180
181 return (ISerializer)ser!;
182 }
183
184 if (targetType.GetGenericTypeDefinition() == typeof(NamedRef<>))
185 {
186 var docType = targetType.GetGenericArguments()[0];
187 var docSerializer = Generate(context, docType);
188
189 var serType = typeof(NamedRefSerializer<>).MakeGenericType(new[] { docType });
190 object? ser = Activator.CreateInstance(serType, new[] { docSerializer });
191
192 return (ISerializer)ser!;
193 }
194
195 if (targetType.IsGenericType && targetType.Name.Contains("AnonymousType"))
196 {
197 return DynamicSerializer.Singleton;
198 }
199 }
200
201
202 if (targetType.IsClass)
203 {
204 var info = context.GetInfo(targetType);
205 return info.ClassSerializer;
206 }
207
208 throw new ArgumentException($"Unsupported deserialization target type {targetType}");
209 }
210
217 public static ISerializer<T?> GenerateNullable<T>(MappingContext context)
218 {
219 var targetType = typeof(T);
220 var ser = (ISerializer<T>)Generate(context, targetType);
221 return new NullableSerializer<T>(ser);
222 }
223
230 public static ISerializer GenerateNullable(MappingContext context, Type targetType)
231 {
232 var inner = (ISerializer)Generate(context, targetType);
233 var serType = typeof(NullableSerializer<>).MakeGenericType(new[] { targetType });
234 var ser = Activator.CreateInstance(serType, new[] { inner });
235
236 return (ISerializer)ser!;
237 }
238
245 public static void Register(Type t, ISerializer s)
246 {
247 if (!_reg.TryAdd(t, s)) throw new ArgumentException($"Serializer for type `{t}` already registered");
248 }
249
255 public static void Register<T>(ISerializer<T> s)
256 {
257 var success = false;
258 foreach (var i in s.GetType().GetInterfaces())
259 {
260 if (!i.IsGenericType || i.GetGenericTypeDefinition() != typeof(ISerializer<>)) continue;
261
262 var t = i.GetGenericArguments()[0];
263 success = _reg.TryAdd(t, s);
264 if (!success) throw new ArgumentException($"Serializer for type `{t}` already registered");
265 break;
266 }
267
268 if (!success) throw new ArgumentException($"Could not infer associated type for `{s.GetType()}`. Use Register(type, serializer).");
269 }
270
275 public static void Deregister(Type t)
276 {
277 if (_reg.ContainsKey(t)) _reg.Remove(t);
278 }
279
280 private static bool IsAnonymousType(this Type type)
281 {
282 bool hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any();
283 bool nameContainsAnonymousType = type?.FullName?.Contains("AnonymousType") ?? false;
284 return hasCompilerGeneratedAttribute && nameContainsAnonymousType;
285 }
286}
System.ArgumentException ArgumentException
A class representing the mapping context to be used during serialization and deserialization.
MappingInfo GetInfo(Type ty, string? colName=null)
Gets the MappingInfo for a given Type.
Represents an FQL query expression. This class encapsulates a list of IQueryFragment instances,...
Definition QueryExpr.cs:11
Represents the abstract base class for constructing FQL queries.
Definition Query.cs:11
Represents a literal part of an FQL query. This class is used for embedding raw string values directl...
Represents a dictionary of FQL queries.
Definition QueryObj.cs:10
Represents a generic value holder for FQL queries. This class allows embedding values of various type...
Definition QueryVal.cs:10
An abstract class representing a reference that can wrap an instance of the referenced document.
Definition BaseRef.cs:10
Represents a Fauna EventSource for initializing Streams and Feeds.
Definition EventSource.cs:9
Represents a module, a singleton object grouping related functionalities. Modules are serialized as @...
Definition Module.cs:8
Represents a document ref that has a "name" instead of an "id". For example, a Role document referenc...
Definition NamedRef.cs:12
Represents a document ref.
Definition Ref.cs:11