Skip to content

Commit 433639f

Browse files
Added naming strategy for value encoder/decoder (#156)
1 parent 96fa373 commit 433639f

File tree

4 files changed

+168
-47
lines changed

4 files changed

+168
-47
lines changed

FaunaDB.Client/Types/Decoder.cs

Lines changed: 100 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,30 @@ public static class Decoder
3535
/// <param name="value">The FaunaDB value to be decoded</param>
3636
/// <typeparam name="T">The type name in which the value should be decoded</typeparam>
3737
public static T Decode<T>(Value value) =>
38-
(T)DecoderImpl.Decode(value, typeof(T));
38+
(T)new DecoderImpl(NamingStrategy.Default).Decode(value, typeof(T), null);
39+
40+
/// <summary>
41+
/// Decode the FaunaDB value into the specified type T.
42+
/// </summary>
43+
/// <example>
44+
/// Decode&lt;int&gt;(LongV.Of(10)) => 10
45+
/// Decode&lt;double&gt;(DoubleV.Of(3.14)) => 3.14
46+
/// Decode&lt;bool&gt;(BooleanV.True) => true
47+
/// Decode&lt;object&gt;(NullV.Instance) => null
48+
/// Decode&lt;string&gt;(StringV.Of("a string")) => "a string"
49+
/// Decode&lt;int[]&gt;(ArrayV.Of(1, 2)) => new int[] { 1, 2 }
50+
/// Decode&lt;List&lt;int&gt;&gt;(ArrayV.Of(1, 2)) => new List&lt;int&gt;&gt; { 1, 2 }
51+
/// Decode&lt;byte[]&gt;(new ByteV(1, 2)) => new byte[] { 1, 2 }
52+
/// Decode&lt;DateTime&gt;(new TimeV("2000-01-01T01:10:30.123Z")) => new DateTime(2000, 1, 1, 1, 10, 30, 123)
53+
/// Decode&lt;DateTime&gt;(new DateV("2001-01-01")) => new DateTime(2001, 1, 1)
54+
/// Decode&lt;User&gt;(ObjectV.With("user_name", "john", "password", "s3cr3t")) => new User("john", "s3cr3t")
55+
/// </example>
56+
/// <returns>An instance of type T</returns>
57+
/// <param name="value">The FaunaDB value to be decoded</param>
58+
/// <param name="namingStrategy">The naming strategy to use</param>
59+
/// <typeparam name="T">The type name in which the value should be decoded</typeparam>
60+
public static T Decode<T>(Value value, NamingStrategy namingStrategy) =>
61+
(T)new DecoderImpl(namingStrategy).Decode(value, typeof(T), null);
3962

4063
/// <summary>
4164
/// Decode the FaunaDB value into the type specified in the argument.
@@ -57,21 +80,57 @@ public static T Decode<T>(Value value) =>
5780
/// <param name="value">The FaunaDB value to be decoded</param>
5881
/// <param name="dstType">The type in which the value should be decoded</param>
5982
public static object Decode(Value value, Type dstType) =>
60-
DecoderImpl.Decode(value, dstType);
83+
new DecoderImpl(NamingStrategy.Default).Decode(value, dstType, null);
84+
85+
/// <summary>
86+
/// Decode the FaunaDB value into the type specified in the argument.
87+
/// </summary>
88+
/// <example>
89+
/// Decode(LongV.Of(10), typeof(int)) => 10
90+
/// Decode(DoubleV.Of(3.14), typeof(double)) => 3.14
91+
/// Decode(BooleanV.True, typeof(bool)) => true
92+
/// Decode(NullV.Instance, typeof(object)) => null
93+
/// Decode(StringV.Of("a string"), typeof(string)) => "a string"
94+
/// Decode(ArrayV.Of(1, 2), typeof(int[])) => new int[] { 1, 2 }
95+
/// Decode(ArrayV.Of(1, 2), typeof(List&lt;int&gt;&gt;)) => new List&lt;int&gt;&gt; { 1, 2 }
96+
/// Decode(new ByteV(1, 2), typeof(byte[])) => new byte[] { 1, 2 }
97+
/// Decode(new TimeV("2000-01-01T01:10:30.123Z"), typeof(DateTime)) => new DateTime(2000, 1, 1, 1, 10, 30, 123)
98+
/// Decode(new DateV("2001-01-01"), typeof(DateTime)) => new DateTime(2001, 1, 1)
99+
/// Decode(ObjectV.With("user_name", "john", "password", "s3cr3t"), typeof(User)) => new User("john", "s3cr3t")
100+
/// </example>
101+
/// <returns>An instance of type specified in the argument</returns>
102+
/// <param name="value">The FaunaDB value to be decoded</param>
103+
/// <param name="dstType">The type in which the value should be decoded</param>
104+
/// <param name="namingStrategy">The naming strategy to use</param>
105+
public static object Decode(Value value, Type dstType, NamingStrategy namingStrategy) =>
106+
new DecoderImpl(namingStrategy).Decode(value, dstType, null);
61107
}
62108

63109
internal class DecoderImpl
64110
{
65111
private static readonly Dictionary<Type, Converter> converters = new Dictionary<Type, Func<Value, object>>();
66112
private static readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
67113

68-
private static InvalidCastException invalidCast(object value, Type to)
114+
private NamingStrategy namingStrategy;
115+
116+
private InvalidCastException invalidCast(object value, Type to)
69117
{
70118
var from = value?.GetType();
71119
return new InvalidCastException($"Invalid cast from '{from}' to '{to}'.");
72120
}
73121

74-
public static object Decode(Value value, Type dstType, Type forceType = null)
122+
public DecoderImpl(NamingStrategy decoderNamingStrategy)
123+
{
124+
namingStrategy = decoderNamingStrategy;
125+
}
126+
127+
public static object Decode(Value value, Type dstType, Type forceType, NamingStrategy namingStrategy)
128+
{
129+
return new DecoderImpl(namingStrategy)
130+
.Decode(value, dstType, forceType);
131+
}
132+
133+
public object Decode(Value value, Type dstType, Type forceType = null)
75134
{
76135
if (value == NullV.Instance && dstType == typeof(Value))
77136
{
@@ -86,7 +145,7 @@ public static object Decode(Value value, Type dstType, Type forceType = null)
86145
return DecodeIntern(value, dstType, forceType);
87146
}
88147

89-
private static object DecodeIntern(Value value, Type dstType, Type forceType = null)
148+
private object DecodeIntern(Value value, Type dstType, Type forceType = null)
90149
{
91150
if (typeof(Value).IsAssignableFrom(dstType))
92151
{
@@ -215,7 +274,7 @@ private static object DecodeIntern(Value value, Type dstType, Type forceType = n
215274
throw invalidCast(value, dstType);
216275
}
217276

218-
private static IEnumerable FromSet(Value value, Type type)
277+
private IEnumerable FromSet(Value value, Type type)
219278
{
220279
if (!(value is ArrayV))
221280
{
@@ -242,7 +301,7 @@ private static IEnumerable FromSet(Value value, Type type)
242301
return set;
243302
}
244303

245-
private static IList FromEnumerable(Value value, Type type)
304+
private IList FromEnumerable(Value value, Type type)
246305
{
247306
if (!(value is ArrayV))
248307
{
@@ -270,7 +329,7 @@ private static IList FromEnumerable(Value value, Type type)
270329
return ret;
271330
}
272331

273-
private static IDictionary FromDictionary(Value value, Type type)
332+
private IDictionary FromDictionary(Value value, Type type)
274333
{
275334
if (!(value is ObjectV))
276335
{
@@ -299,7 +358,7 @@ private static IDictionary FromDictionary(Value value, Type type)
299358
return ret;
300359
}
301360

302-
private static Array FromArray(Value value, Type type)
361+
private Array FromArray(Value value, Type type)
303362
{
304363
var elementType = type.GetElementType();
305364

@@ -320,7 +379,7 @@ private static Array FromArray(Value value, Type type)
320379
return ret;
321380
}
322381

323-
private static object ToNumber<R>(Value value)
382+
private object ToNumber<R>(Value value)
324383
{
325384
var ll = value as ScalarValue<long>;
326385
if (ll != null)
@@ -343,19 +402,19 @@ private static object ToNumber<R>(Value value)
343402
throw invalidCast(value, typeof(R));
344403
}
345404

346-
private static string ToString(Value value) =>
405+
private string ToString(Value value) =>
347406
FromScalar<string>(value, typeof(string));
348407

349-
private static bool ToBoolean(Value value) =>
408+
private bool ToBoolean(Value value) =>
350409
FromScalar<bool>(value, typeof(bool));
351410

352-
private static DateTime ToDateTime(Value value) =>
411+
private DateTime ToDateTime(Value value) =>
353412
FromScalar<DateTime>(value, typeof(DateTime));
354413

355-
private static byte[] ToByteArray(Value value) =>
414+
private byte[] ToByteArray(Value value) =>
356415
FromScalar<byte[]>(value, typeof(byte[]));
357416

358-
private static T FromScalar<T>(Value value, Type type)
417+
private T FromScalar<T>(Value value, Type type)
359418
{
360419
var scalar = value as ScalarValue<T>;
361420

@@ -367,7 +426,7 @@ private static T FromScalar<T>(Value value, Type type)
367426
return scalar.Value;
368427
}
369428

370-
private static object ToEnum(Value value, Type dstType)
429+
private object ToEnum(Value value, Type dstType)
371430
{
372431
Converter converter;
373432

@@ -396,7 +455,7 @@ private static object ToEnum(Value value, Type dstType)
396455
return converter.Invoke(value);
397456
}
398457

399-
private static object FromObject(Value value, Type dstType)
458+
private object FromObject(Value value, Type dstType)
400459
{
401460
Converter converter;
402461

@@ -430,7 +489,7 @@ private static object ThrowError(Value value, Type dstType)
430489
throw new InvalidOperationException($"Enumeration value '{((StringV)value).Value}' not found in {dstType}");
431490
}
432491

433-
private static Converter CreateEnumConverter(Type dstType)
492+
private Converter CreateEnumConverter(Type dstType)
434493
{
435494
var objExpr = Expression.Parameter(typeof(Value), "obj");
436495
var varExpr = Expression.Variable(dstType, "output");
@@ -457,7 +516,7 @@ private static Converter CreateEnumConverter(Type dstType)
457516
.Compile();
458517
}
459518

460-
private static SwitchCase CreateSwitchCase(Enum enumValue)
519+
private SwitchCase CreateSwitchCase(Enum enumValue)
461520
{
462521
var dstType = enumValue.GetType();
463522
var enumName = Enum.GetName(dstType, enumValue);
@@ -472,7 +531,7 @@ private static SwitchCase CreateSwitchCase(Enum enumValue)
472531
typeof(string)));
473532
}
474533

475-
private static Converter CreateConverter(Type dstType)
534+
private Converter CreateConverter(Type dstType)
476535
{
477536
var creator = GetCreator(dstType);
478537

@@ -495,7 +554,7 @@ private static Converter CreateConverter(Type dstType)
495554
return FromConstructor(constructor, dstType);
496555
}
497556

498-
private static MethodInfo GetCreator(Type dstType)
557+
private MethodInfo GetCreator(Type dstType)
499558
{
500559
var methods = dstType
501560
.GetMethods(BindingFlags.Public | BindingFlags.Static)
@@ -514,7 +573,7 @@ private static MethodInfo GetCreator(Type dstType)
514573
return null;
515574
}
516575

517-
private static ConstructorInfo GetConstructor(Type dstType)
576+
private ConstructorInfo GetConstructor(Type dstType)
518577
{
519578
var constructors = dstType
520579
.GetConstructors()
@@ -533,19 +592,19 @@ private static ConstructorInfo GetConstructor(Type dstType)
533592
return dstType.GetConstructor(Type.EmptyTypes);
534593
}
535594

536-
private static Expression AssignProperties(Expression objExpr, Expression varExpr, Type dstType, IEnumerable<string> ignoreProperties)
595+
private Expression AssignProperties(Expression objExpr, Expression varExpr, Type dstType, IEnumerable<string> ignoreProperties)
537596
{
538597
var fields = dstType
539598
.GetAllFields()
540-
.Where(f => !ignoreProperties.Contains(f.GetName()))
599+
.Where(f => !ignoreProperties.Contains(f.GetName(namingStrategy)))
541600
.Where(f => !f.Has<CompilerGeneratedAttribute>() && !f.Has<FaunaIgnoreAttribute>())
542-
.Select(f => Expression.Assign(Expression.Field(varExpr, f), CallDecode(CallGetValue(objExpr, f, f.FieldType), f.FieldType, f.GetOverrideType())));
601+
.Select(f => Expression.Assign(Expression.Field(varExpr, f), CallDecode(CallGetValue(objExpr, f, f.FieldType), f.FieldType, f.GetOverrideType(), namingStrategy)));
543602

544603
var properties = dstType
545604
.GetProperties()
546-
.Where(p => !ignoreProperties.Contains(p.GetName()))
605+
.Where(p => !ignoreProperties.Contains(p.GetName(namingStrategy)))
547606
.Where(p => p.CanWrite && !p.Has<FaunaIgnoreAttribute>())
548-
.Select(p => Expression.Assign(Expression.MakeMemberAccess(varExpr, p), CallDecode(CallGetValue(objExpr, p, p.PropertyType), p.PropertyType, p.GetOverrideType())));
607+
.Select(p => Expression.Assign(Expression.MakeMemberAccess(varExpr, p), CallDecode(CallGetValue(objExpr, p, p.PropertyType), p.PropertyType, p.GetOverrideType(), namingStrategy)));
549608

550609
var concat = fields.Concat(properties);
551610

@@ -554,16 +613,16 @@ private static Expression AssignProperties(Expression objExpr, Expression varExp
554613
: (Expression)Expression.Empty();
555614
}
556615

557-
private static Converter Create(Func<IEnumerable<Expression>, Expression> creatorExpr, ParameterInfo[] parameters, Type dstType)
616+
private Converter Create(Func<IEnumerable<Expression>, Expression> creatorExpr, ParameterInfo[] parameters, Type dstType)
558617
{
559618
var objExpr = Expression.Parameter(typeof(Value), "obj");
560619
var varExpr = Expression.Variable(dstType, "output");
561620
var target = Expression.Label(dstType);
562621

563622
var parametersExpr = parameters
564-
.Select(p => CallDecode(CallGetValue(objExpr, p), p.ParameterType, p.GetOverrideType()));
623+
.Select(p => CallDecode(CallGetValue(objExpr, p), p.ParameterType, p.GetOverrideType(), namingStrategy));
565624

566-
var ignoreProperties = parameters.Select(p => p.GetName());
625+
var ignoreProperties = parameters.Select(p => p.GetName(namingStrategy));
567626

568627
var block = Expression.Block(
569628
new ParameterExpression[] { varExpr },
@@ -588,7 +647,7 @@ private static Converter Create(Func<IEnumerable<Expression>, Expression> creato
588647
* return output;
589648
* }
590649
*/
591-
private static Converter FromValueType(Type dstType)
650+
private Converter FromValueType(Type dstType)
592651
{
593652
return Create(
594653
_ => Expression.New(dstType),
@@ -611,7 +670,7 @@ private static Converter FromValueType(Type dstType)
611670
* return output;
612671
* }
613672
*/
614-
private static Converter FromConstructor(ConstructorInfo constructor, Type dstType)
673+
private Converter FromConstructor(ConstructorInfo constructor, Type dstType)
615674
{
616675
return Create(
617676
p => Expression.New(constructor, p),
@@ -634,7 +693,7 @@ private static Converter FromConstructor(ConstructorInfo constructor, Type dstTy
634693
* return output;
635694
* }
636695
*/
637-
private static Converter FromMethodCreator(MethodInfo creator, Type dstType)
696+
private Converter FromMethodCreator(MethodInfo creator, Type dstType)
638697
{
639698
return Create(
640699
p => Expression.Call(creator, p),
@@ -646,23 +705,23 @@ private static Converter FromMethodCreator(MethodInfo creator, Type dstType)
646705
/*
647706
* Decode( objExpr, type )
648707
*/
649-
private static Expression CallDecode(Expression objExpr, Type type, Type overrideType = null)
708+
private Expression CallDecode(Expression objExpr, Type type, Type overrideType, NamingStrategy namingStrategy)
650709
{
651710
var decodeMethod = typeof(DecoderImpl).GetMethod(
652-
"Decode", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Value), typeof(Type), typeof(Type) }, null
711+
"Decode", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Value), typeof(Type), typeof(Type), typeof(NamingStrategy) }, null
653712
);
654713

655714
var decodeExpr = Expression.Call(
656715
decodeMethod,
657-
new Expression[] { objExpr, Expression.Constant(type), Expression.Constant(overrideType, typeof(Type)) }
716+
new Expression[] { objExpr, Expression.Constant(type), Expression.Constant(overrideType, typeof(Type)), Expression.Constant(namingStrategy, typeof(NamingStrategy)) }
658717
);
659718

660719
return type.GetTypeInfo().IsValueType
661720
? Expression.Unbox(decodeExpr, type)
662721
: Expression.Convert(decodeExpr, type);
663722
}
664723

665-
private static Expression CallGetValue(Expression objExpr, MemberInfo member, Type memberType)
724+
private Expression CallGetValue(Expression objExpr, MemberInfo member, Type memberType)
666725
{
667726
var field = member.GetCustomAttribute<FaunaFieldAttribute>();
668727
var defaultValue = field != null ? Encoder.Encode(field.DefaultValue) : null;
@@ -683,10 +742,10 @@ private static Expression CallGetValue(Expression objExpr, MemberInfo member, Ty
683742
return Expression.Constant(defaultValue, typeof(Value));
684743
}
685744

686-
return CallGetValue(objExpr, member.GetName(), defaultValue);
745+
return CallGetValue(objExpr, member.GetName(namingStrategy), defaultValue);
687746
}
688747

689-
private static Expression CallGetValue(Expression objExpr, ParameterInfo parameter)
748+
private Expression CallGetValue(Expression objExpr, ParameterInfo parameter)
690749
{
691750
var field = parameter.GetCustomAttribute<FaunaFieldAttribute>();
692751
var hasDefaultValue = field != null && field.DefaultValue != null;
@@ -710,13 +769,13 @@ private static Expression CallGetValue(Expression objExpr, ParameterInfo paramet
710769
return Expression.Constant(defaultValue, typeof(Value));
711770
}
712771

713-
return CallGetValue(objExpr, parameter.GetName(), defaultValue);
772+
return CallGetValue(objExpr, parameter.GetName(namingStrategy), defaultValue);
714773
}
715774

716775
/*
717776
* GetValue( objExpr, property, defaultValue )
718777
*/
719-
private static Expression CallGetValue(Expression objExpr, string property, Value defaultValue)
778+
private Expression CallGetValue(Expression objExpr, string property, Value defaultValue)
720779
{
721780
var getValueMethod = typeof(DecoderImpl).GetMethod(
722781
"GetValue", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(ObjectV), typeof(string), typeof(Value) }, null

0 commit comments

Comments
 (0)